构造函数和属性注入使您可以轻松地在非CDI环境中(例如,单元测试)初始化对象。
在非CDI环境中,您仍然可以通过传递构造函数arg来简单地使用对象。
OtherBean b = ....;new MyBean(b);
如果仅使用字段注入,则通常必须使用反射来访问字段,因为字段通常是私有的。
如果使用属性注入,则还可以在设置器中编写代码。例如,验证代码或您清除内部高速缓存,这些内部高速缓存保存的值是从setter修改的属性中得出的。您想做什么取决于您的实施需求。
设置器与构造器注入
在面向对象的编程中,对象在构造后必须处于有效状态,并且每次方法调用都将状态更改为另一个有效状态。
对于setter注入,这意味着您可能需要更复杂的状态处理,因为即使构造器尚未被调用,对象在构造后仍应处于有效状态。因此,即使未设置该属性,对象也必须处于有效状态。例如,使用默认值或空对象。
如果对象的存在与属性之间存在依赖关系,则该属性应为构造函数参数。这还将使代码更清晰,因为如果您使用构造函数参数,则说明需要依赖。
所以不要写这样的课
public class CustomerDaoImpl implements CustomerDao { private DataSource dataSource; public Customer findById(String id){ checkDataSource(); Connection con = dataSource.getConnection(); ... return customer; } private void checkDataSource(){ if(this.dataSource == null){ throw new IllegalStateException("dataSource is not set"); } } public void setDataSource(DataSource dataSource){ this.dataSource = dataSource; }}您应该使用构造函数注入
public class CustomerDaoImpl implements CustomerDao { private DataSource dataSource; public CustomerDaoImpl(DataSource dataSource){ if(dataSource == null){ throw new IllegalArgumentException("Parameter dataSource must not be null"); } this.dataSource = dataSource; } public Customer findById(String id) { Customer customer = null; // We can be sure that the dataSource is not null Connection con = dataSource.getConnection(); ... return customer; }}我的结论
- 对每个 可选依赖项* 使用 属性 。 *
- 对每个 强制性依赖项* 使用 构造函数args 。 *
PS:我的博客pojos和Java bean之间的区别更详细地说明了我的结论。
编辑
Spring还建议使用构造函数注入,正如我在Spring文档的基于Setter的依赖注入中所发现的那样。
Spring团队通常提倡构造函数注入,因为它可以让您将应用程序组件实现为不可变对象,并确保所需的依赖项不为null。此外,注入构造函数的组件始终以完全初始化的状态返回到客户端(调用)代码。附带说明一下,大量的构造函数自变量是一种不好的代码味,这表明该类可能承担了太多的职责,应将其重构以更好地解决关注点分离问题。
Setter注入主要应仅用于可以在类中分配合理的默认值的可选依赖项。否则,必须在代码使用依赖项的任何地方执行非空检查。setter注入的一个好处是,setter方法使该类的对象在以后可以重新配置或重新注入。因此,通过JMX
MBean进行管理是用于setter注入的引人注目的用例。
考虑单元测试时,构造函数注入也是一种更好的方法,因为调用构造函数比设置私有(@Autowired)字段更容易。



