为什么在CDI中使用建立者超过setter注入? [英] Why use constructor over setter injection in CDI?

查看:143
本文介绍了为什么在CDI中使用建立者超过setter注入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里找不到任何合理的答案,所以我希望它不是重复的。那么为什么我更喜欢setter或者构造函数注入简单的

  @Inject 
MyBean bean;

如果您在类初始化期间需要使用注入的bean来处理构造函数注入的使用像

  public void MyBean(@Inject OtherBean bean){
doSomeInit(bean);
//我不需要使用@PostConstruct
}

但是,它仍然像 @PostConstruct 方法几乎一样,我根本不会得到setter注入,这不是Spring和其他DI框架之后的遗迹吗? / p>

解决方案

构造器和属性注入使您可以轻松地在非CDI环境中初始化对象,例如单元测试。 / p>

在非CDI环境中,您仍然可以通过传递构造函数arg来简单地使用该对象。

  OtherBean b = ....; 
new MyBean(b);

如果您只是使用字段注入,您必须使用反射来访问该字段,如果它是私有的。



如果您使用属性注入,还可以在setter中编写代码。所以这取决于您的实现需求。



Setter与构造函数注入



在面向对象的编程中,对象必须在构建之后处于有效状态,并且每个方法调用将状态更改为另一个有效状态。



对于setter注入,这意味着您可能需要更复杂的状态处理,因为物件在施工后应处于有效状态。即使尚未调用setter。因此,即使没有设置属性,对象也必须处于有效状态。例如。使用默认值或空对象



如果对象的存在和属性之间存在依赖关系,则属性应该是构造函数参数。这也将使代码更干净,因为如果使用构造函数参数,则记录依赖关系是必需的。



所以,而不是写这样的类

  public class CustomerDaoImpl实现CustomerDao {

private DataSource dataSource;

public客户findById(String id){
//数据源设置?
连接con = dataSource.getConnection();
...
返回客户;
}

public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}

}

您应该使用构造函数注入

  public class CustomerDaoImpl实现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;
//我们可以确保dataSource不为空
连接con = dataSource.getConnection();
...
返回客户;
}
}



我的结论




  • 对于每个可选依赖关系使用属性

  • 使用构造函数



PS:我的博客 pojos和java bean之间的区别更详细地解释了我的结论。


I couldn't find any reasonable answer here on SO so I hope it's not a duplicate. So why should I prefer setter or constructor injection over simple

@Inject
MyBean bean;

I get the usage of the constructor injection if you need to do something with injected bean during your class initialization like

public void MyBean(@Inject OtherBean bean) {
    doSomeInit(bean);
    //I don't need to use @PostConstruct now
}

but still, it's almost the same like @PostConstruct method and I don't get setter injection at all, isn't it just a relic after Spring and other DI frameworks?

解决方案

Constructor and property injection gives you the option to initialize the object even in a non CDI environment easily, e.g a unit test.

In a non-CDI environment you can still simply use the object by just passing the constructor arg.

OtherBean b = ....;
new MyBean(b);

If you just use field injection you must use reflection to access the field if it is private for example.

If you use property injection you can also write code in the setter. So it depends on your implementation needs.

Setter vs constructor injection

In object-oriented programming an object must be in a valid state after construction and every method invocation changes the state to another valid state.

For setter injection this means that you might require a more complex state handling, because an object should be in a valid state after construction. Even if the setter has not been invoked yet. Thus the object must be in a valid state even if the property is not set. E.g. by using a default value or a null object.

If you have a dependency between the object's existence and the property, the property should either be a constructor argument. This will also make the code more clean, because if you use a constructor parameter you document that the dependency is necessary.

So instead of writing a class like this

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;
  }

}

you should either use constructor injection

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;
  }
}

My conclusion

  • Use properties for every optional dependency.
  • Use constructor args for every mandatory dependency.

PS: My blog The difference between pojos and java beans explains my conclusion in more detail.

这篇关于为什么在CDI中使用建立者超过setter注入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆