1. 字段注入 (Field Injection) - 最常见但不推荐
当你将 @Autowired 注解直接标注在字段(成员变量) 上时,Spring会通过反射机制直接设置该字段的值,即使它是 private 的。
@Service
public class UserService {
@Autowired // 字段注入
private UserRepository userRepository;
// ...
}
-
方式:字段注入
-
特点:代码非常简洁,但也是最不推荐的方式(原因见后文)。
2. Setter 方法注入 (Setter Injection)
当你将 @Autowired 注解标注在对应的 Setter方法 上时,Spring会在构造完对象后,调用这个Setter方法来注入依赖。
@Service
public class UserService {
private UserRepository userRepository;
@Autowired // Setter方法注入
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
-
方式:Setter注入
-
特点:比字段注入更灵活,允许在对象创建后重新配置依赖(但通常不需要这么做)。
3. 构造函数注入 (Constructor Injection) - 官方推荐的最佳实践
当你将 @Autowired 注解标注在类的构造函数上时,Spring会通过调用这个构造函数来创建对象,并将所需的依赖作为参数传入。
注意:在Spring 4.3及以后的版本中,如果一个类只有一个构造函数,那么 @Autowired 注解可以省略,Spring会自动使用该构造函数进行注入。
@Service
public class UserService {
private final UserRepository userRepository;
// @Autowired 注解在只有一个构造函数时可省略
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
-
方式:构造函数注入
-
特点:这是目前最推荐的方式。
总结与对比
| 注入方式 | 代码示例 | 优点 | 缺点 |
|---|---|---|---|
| 字段注入 | @Autowired private Foo foo; | 代码极其简洁 | 1. 不易测试(必须通过反射或启动容器来注入) 2. 无法声明为 final(破坏了不可变性)3. 容易导致空指针(如果容器配置错误,字段为 null)4. 破坏封装性(通过反射强制给私有字段赋值) |
| Setter注入 | @Autowired public void setFoo(Foo f) | 灵活性高,允许可选依赖或重新注入 | 对象可能在Set之前被使用,导致状态不完整 |
| 构造函数注入 | @Autowired public ClassA(Foo f) | 1. 强依赖性:保证对象在构造完成后就处于完全初始化的状态 2. 不可变:依赖可声明为 final3. 易于测试:不依赖容器,可直接通过 new 传入Mock对象进行测试4. 代码安全:避免空指针问题 | 依赖过多时,构造函数参数列表会很长 |
最佳实践
强烈推荐优先使用构造函数注入。 这是Spring官方自4.x版本以来倡导的方式,理由如下:
-
不可变性:
final字段保证了依赖在对象生命周期内不会被意外更改。 -
完全初始化的状态:对象一旦被创建,其所有必需依赖都已就绪,避免了部分初始化的不一致状态。
-
更好的可测试性:你可以毫不费力地编写单元测试,只需简单地调用构造函数并传入模拟依赖。
-
代码更清晰:构造函数明确地声明了创建一个该类的实例所必须的依赖项。
2175

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



