我在这里找不到任何合理的答案所以我希望它不是重复的。那么为什么我更喜欢setter或构造函数注入而不是简单
@Inject
MyBean bean;
如果你需要在类初始化期间对注入的bean执行某些操作,我会使用构造函数注入
public void MyBean(@Inject OtherBean bean) {
doSomeInit(bean);
//I don't need to use @PostConstruct now
}
但是,它几乎一样 @PostConstruct
方法,我根本没有得到setter注入,它不仅仅是Spring和其他DI框架之后的遗物吗?
构造函数和属性注入使您可以轻松地在非CDI环境中初始化对象,例如单元测试。
在非CDI环境中,您仍然可以通过传递构造函数arg来简单地使用该对象。
OtherBean b = ....;
new MyBean(b);
如果您只是使用场注入,则必须使用反射来访问该字段(例如,如果它是私有的)。
如果使用属性注入,也可以在setter中编写代码。所以这取决于您的实施需求。
塞特与构造函数注入
在面向对象的编程中,对象在构造之后必须处于有效状态,并且每个方法调用都将状态更改为另一个有效状态。
对于setter注入,这意味着您可能需要更复杂的状态处理,因为对象在构造之后应该处于有效状态。即使尚未调用setter。因此,即使未设置属性,对象也必须处于有效状态。例如。使用默认值或 null对象。
如果对象的存在与属性之间存在依赖关系,则该属性应该是构造函数参数。这也将使代码更加干净,因为如果使用构造函数参数,则需要记录依赖项。
所以不要写这样的课
public class CustomerDaoImpl implements CustomerDao {
private DataSource dataSource;
public Customer findById(String id){
// Is the dataSource set?!
Connection con = dataSource.getConnection();
...
return customer;
}
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之间的区别 更详细地解释了我的结论。
使用CDI时,没有任何理由使用构造函数或setter注入。如问题中所述,您添加了一个 @PostConstruct
在构造函数中以其他方式完成的方法。
其他人可能会说你需要使用Reflection在单元测试中注入字段,但事实并非如此;模拟库和其他测试工具为您做到这一点。
最后,构造函数注入允许字段 final
,但这不是一个真正的缺点 @Inject
注释字段(不能是 final
)。注释的存在,加上没有明确设置字段的任何代码,应该清楚地表明它只能由容器(或测试工具)设置。在实践中,没有人会重新分配注入的场。
构造函数和setter注入在过去是有意义的,当开发人员通常不得不手动实例化并将依赖项注入到测试对象中时。如今,技术已经发展,现场注入是一个更好的选择。