当前位置: 首页 > 面试题库 >

为什么在CDI中使用构造函数而不是setter注入?

程峻
2023-03-14
问题内容

我在这里找不到任何合理的答案,所以我希望它不会重复。那么为什么我应该更喜欢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注入,这意味着您可能需要更复杂的状态处理,因为即使构造器尚未被调用,对象在构造后仍应处于有效状态。因此,即使未设置该属性,对象也必须处于有效状态。例如,使用默认值或空对象。

如果对象的存在与属性之间存在依赖关系,则该属性应为构造函数参数。这还将使代码更清晰,因为如果您使用构造函数参数,则说明需要依赖。

所以不要写这样的课

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团队通常提倡构造函数注入,因为它可以让您将应用html" target="_blank">程序组件实现为不可变对象,并确保所需的依赖项不为null。此外,注入构造函数的组件始终以完全初始化的状态返回到客户端(调用)代码。附带说明一下,大量的构造函数自变量是一种不好的代码味,这表明该类可能承担了太多的职责,应将其重构以更好地解决关注点分离问题。

Setter注入主要应仅用于可以在类中分配合理的默认值的可选依赖项。否则,必须在代码使用依赖项的任何地方执行非空检查。setter注入的一个好处是,setter方法使该类的对象在以后可以重新配置或重新注入。因此,通过JMX
MBean进行管理是用于setter注入的引人注目的用例。

考虑单元测试时,构造函数注入也是一种更好的方法,因为调用构造函数比设置私有(@Autowired)字段更容易。



 类似资料:
  • 我试图将构造函数注入模式应用于CDI应用程序中的bean,但遇到以下错误消息: 的确,为了使用构造函数注入模式,我有意地设计了一个需要参数的构造函数的类: 通过查看不可代理bean类型的CDI规范,我看到: 3.15.不可修复的bean类型 容器使用代理提供某些功能。容器不能代理某些合法bean类型: 没有不带参数的非私有构造函数的类, 被宣布为最终的类, 具有非静态的、具有公共可见性、受保护可见

  • 问题内容: 在Jackson中,当您使用注释构造函数时,必须使用注释其参数。所以这个构造函数 变成这个: 我不明白为什么有必要。你能解释一下吗? 问题答案: Jackson必须知道以什么顺序将字段从JSON对象传递给构造函数。使用反射无法在Java中访问参数名称-这就是为什么您必须在注释中重复此信息的原因。

  • 请帮助理解在哪种情况下我应该使用构造函数注入和设置器注入。请帮我举个合适的例子。 先谢谢你。

  • 在尝试向CDI bean(ApplicationScoped)的构造函数中注入参数时,我遇到了以下问题: 但是,我在类上确实有一个可注入的构造函数: 有什么想法这里出了什么问题吗?

  • 问题内容: 我是Java编程语言的初学者,最近我研究了 构造函数 不能在Java中继承,有人可以解释 为什么 吗? 问题答案: 简而言之,构造函数不能被继承,因为在子类中它具有​​不同的名称(子类的名称)。 您只能执行以下操作: 相反,方法是使用“相同名称”继承的,可以使用。 理由如下:继承构造函数没有多大意义,因为类A的构造函数意味着创建类型A的对象,而类B的构造函数意味着创建类B的对象。 不过