一、依赖注入(DI)概述
依赖注入是现代 Java 框架(如 Spring)的核心思想。它通过将对象所依赖的组件从外部注入,解耦代码依赖,提高代码的可测试性和扩展性。
1. 构造器注入(Constructor Injection)
构造器注入是通过类的有参构造函数传入依赖,确保依赖在对象创建时就已经赋值。
@Service
public class UserService {
private final UserRepository userRepository;
// 构造器注入,依赖注入时由 Spring 自动调用此构造函数
public UserService(UserRepository userRepository) {
this.userRepository = userRepository; }
public void createUser() { userRepository.save(); } }
优点:
-
依赖为
final,不可变,线程安全。 -
必须提供依赖,避免空指针。
-
方便单元测试,明确依赖。
2. 注解注入(@Autowired)
通过注解标注字段、构造器或 setter,Spring 会自动注入依赖。
字段注入示例(不推荐):
@Service public class UserService {
@Autowired private UserRepository userRepository;
public void createUser() {
userRepository.save(); } }
setter 注入示例:
@Service public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository; } }
**注意:**字段注入可能导致构造过程中依赖为 null,容易出现空指针异常。
3. 为什么推荐构造器注入?
-
Spring 容器在调用构造器时,依赖已经准备好,避免构造函数里使用未注入依赖导致空指针。
-
依赖明确,代码更加安全和易维护。
-
单元测试方便,只需传入 mock 对象。
二、Java 反射基础及示例
反射是 Java 提供的一种运行时动态访问和操作类的机制。
1. 反射能做什么?
-
动态获取类的结构(字段、方法、构造器)
-
动态创建对象实例
-
动态调用方法
-
访问私有成员(破坏封装)
2. 反射示例代码
假设有如下 User 类:
public class User {
private String name = "默认";
public User() {} public User(String name) {
this.name = name; }
public void sayHello() {
System.out.println("Hello, I am " + name); }
public void setName(String name) { this.name = name; } }
用反射创建对象并调用方法:
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 1. 获取类对象
Class<?> clazz = Class.forName("User");
// 2. 创建无参构造对象
Object user = clazz.getDeclaredConstructor().newInstance();
// 3. 调用 setName 方法
Method setName = clazz.getMethod("setName", String.class);
setName.invoke(user, "Alice");
// 4. 调用 sayHello 方法
Method sayHello = clazz.getMethod("sayHello");
sayHello.invoke(user); } }
输出:
css
复制编辑
Hello, I am Alice
3. 为什么有时候不用直接 new?
因为:
-
代码编写时不一定知道要使用哪个类
-
框架需要根据类名字符串动态加载类实例
-
实现插件、配置驱动的动态扩展
反射使代码更加灵活、可扩展。
三、Spring AOP 与动态增强
1. 什么是 AOP?
AOP(面向切面编程)允许我们将日志、事务、权限等横切关注点抽离出来,动态地织入业务逻辑中,而不用修改业务代码。
2. 动态增强的概念
动态增强指的是在运行时,通过代理和反射技术,在方法执行前后或异常时插入额外代码。
3. Spring AOP 实现原理简述
-
Spring 使用 JDK 动态代理或 CGLIB 动态代理创建目标类代理。
-
代理类的方法调用会被拦截,执行增强逻辑(通知)。
-
最终通过反射调用原始目标方法。
4. AOP 代码示例
定义切面:
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice() { System.out.println("方法执行前打印日志"); } @AfterReturning("execution(* com.example.service.*.*(..))")
public void afterAdvice() {
System.out.println("方法执行后记录操作");
} }
调用业务方法时:
orderService.createOrder();
实际调用流程:
scss
代理对象的 createOrder() -> 执行 beforeAdvice() -> 通过反射调用真实 createOrder() -> 执行 afterAdvice()
5. 反射在 AOP 中的作用
反射用于:
-
获取方法信息,动态判断调用哪个方法
-
调用目标方法(
Method.invoke()) -
动态实现通知(前置、后置、异常)
四、总结
| 主题 | 关键点 |
|---|---|
| 依赖注入 | 构造器注入推荐,字段注入易空指针 |
| 反射 | 运行时动态访问类信息,动态创建对象和调用方法 |
| 为什么不用 new | 编译时绑定,反射支持运行时灵活动态加载 |
| AOP 与动态增强 | 利用代理和反射动态织入横切逻辑 |
564

被折叠的 条评论
为什么被折叠?



