前言
构造器注入和Setter注入是依赖注入(Dependency Injection,DI)中两种常见的方式,用于向一个对象注入其所依赖的其他对象或数值。这两种注入方式有各自的特点和用途。
构造器注入(Constructor Injection):
在构造器注入中,依赖关系通过类的构造函数传递。这意味着在创建对象时,依赖的对象实例会作为构造函数的参数传递进来。
示例(Java):
代码语言:javascript复制public class UserService {
private UserRepository userRepository;
// 构造器注入
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 其他方法使用userRepository
}
优点:
- 对象的依赖关系在创建时就被确定,对象一旦创建就不可变,有助于保持对象的一致性和可靠性。
- 在构造函数中明确声明依赖,可以使类的使用更加清晰,减少了后续对依赖的猜测。
Setter注入(Setter Injection):
在Setter注入中,依赖通过类的setter方法进行注入。这意味着你可以在对象创建后随时改变依赖关系。
示例(Java):
代码语言:javascript复制public class UserService {
private UserRepository userRepository;
// Setter注入
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 其他方法使用userRepository
}
优点:
- 灵活性高,可以在运行时动态更改依赖关系。
- 允许逐步构建对象,不需要一次性提供所有依赖。
选择构造器注入还是Setter注入取决于以下因素:
- 不变性需求: 如果对象的依赖关系在创建后不应该更改,构造器注入是一个好的选择。
- 灵活性需求: 如果对象的依赖关系可能在运行时更改,Setter注入更为合适。
- 清晰性: 构造器注入通常更容易理解,因为依赖关系在对象创建时就被确定。
- 依赖数量: 如果类有大量的依赖,构造器注入可能更清晰,而不是在构造函数中添加大量的参数。
在实践中,有时也可以使用构造器注入和Setter注入的组合,以满足不同的需求。
当前Spring Framework版本对两者的看法
Spring Framework是一个流行的Java开发框架,它提供了丰富的功能,包括依赖注入(Dependency Injection)的支持。Spring对构造器注入和Setter注入都提供了良好的支持,而且在不同版本中,它并没有显著改变对这两种注入方式的看法。当前版本Spring Framework更推荐通过构造方法注入Bean。
来自“Constructor-based or setter-based DI”
“The Spring team generally advocates constructor injection, as it lets
you implement application components as immutable objects and ensures that required dependencies are not null.
Spring团队通常提倡构造函数注入,因为它允许
将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。
Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.
此外,构造器注入的组件总是以完全初始化的状态返回给客户端(调用)代码。顺便说一句,大量的构造函数参数是一种不好的代码气味,这意味着类可能有太多的职责,应该重构以更好地解决适当的关注点分离问题。
Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later.
Management through JMX MBeans is therefore a compelling use case for setter injection.”
Setter注入应该主要只用于可选的依赖项,这些依赖项可以在类中被分配合理的默认值。否则,必须在代码使用依赖项的任何地方执行非空检查。setter注入的一个好处是,setter方法使该类的对象可以在以后重新配置或重新注入。
因此,通过JMX MBeans进行管理是setter注入的一个引人注目的用例。”
总结
总结以上论点就是:
- 构造器注入提倡不可变性: 通过构造器注入对象,实现了对象初始化后的不可变性,同时确保所需依赖不为空。这有助于保持对象状态的稳定性。
- 构造器注入促使代码质量提升: 通过构造器注入,可以清晰地看到类的依赖关系,大量构造器参数说明当前类耦合过多、职责过多,从而促使编码者考虑是否需要重构,以提高代码质量和可维护性。
- Setter注入适用于可选依赖: Setter注入主要用于可选依赖,这些依赖可以在类内部被合理默认赋值。然而,需要注意的是,Setter注入的对象需要进行非空检查,因为它们具有可变性。
- Setter注入支持对象的动态重配置: 通过Setter注入,对象可以在运行时进行重新配置或重新注入。这使得Setter注入在JMX MBeans等需要动态管理的场景下变得特别有用。