【问题标题】:Dependency injection with autowire="constructor" when multiple constructors are present?存在多个构造函数时使用 autowire="constructor" 进行依赖注入?
【发布时间】:2014-02-20 11:27:02
【问题描述】:

我有带有以下构造函数的文本编辑器类

 public class TextEditor {
       private SpellChecker spellChecker;

       private SpellChecker1 spellChecker1;

       private SpellChecker2 spellChecker2;

     public TextEditor(SpellChecker spellChecker) {
          this.spellChecker = spellChecker;
        }

       public TextEditor(SpellChecker2 spellChecker2) {
              this.spellChecker2 = spellChecker2;
           }

       public TextEditor(SpellChecker spellChecker, SpellChecker1 spellChecker1,SpellChecker2 spellChecker2) {
              this.spellChecker = spellChecker;
              this.spellChecker1 = spellChecker1;
              this.spellChecker2 = spellChecker2;
           }

       public TextEditor(SpellChecker spellChecker, SpellChecker1 spellChecker1) {
              this.spellChecker = spellChecker;
              this.spellChecker1 = spellChecker1;
           }
        }

在春豆里我有

<bean id="textEditor" class="com.TextEditor" autowire="constructor">
</bean>

我观察到的是具有两个参数的构造函数被一致地调用。是随机的吗?不应该 spring 抛出异常,因为它不知道需要调用哪个构造函数?

【问题讨论】:

  • 为什么它不知道需要调用哪个构造函数。它根据可用的构造函数确定要注入的类型,在上下文中检查哪个构造函数最能满足并执行该构造函数。
  • 那为什么不调用带有 3 个参数的构造函数呢?
  • SpellChecker2 类型的bean 可用吗?没有完整的画面,很难说。
  • 正如你所说的“spring会在上下文中检查哪个构造函数最多可以满足”。您的意思是说将调用具有最大参数数量的构造函数?
  • @MSach 正如@MDeinum 所暗示的那样,如果您发布了整个 spring-beans xml 文件,它将对读者有所帮助。 @MDeinum 建议您的 spring-beans 文件中有 SpellCheckerSpellChecker1 类型的 bean,但没有 SpellChecker2

标签: java spring


【解决方案1】:

这是 Spring 自动装配构造函数的结果。

它做的第一件事是获取所有 bean 类的构造函数并对其进行排序,将公共构造函数放在首位,参数数量减少,然后再次将所有非公共构造函数放在参数数量减少的位置。这些是候选构造函数。

然后它遍历这些候选对象,尝试从BeanFactory 生成参数。如果由于缺少 bean 或任何其他原因而不能,它会跳过候选者。如果成功找到参数,它会根据许多因素(参数列表长度、参数类型与参数的接近程度等)为当前候选构造函数赋予权重。然后它会检查前一个候选人的体重,如果一个比另一个好,则交换它们。

如果在这个过程结束时有一个候选构造函数,Spring就会使用它。

如果您说 Spring 使用 2 arg 构造函数而不是 3 arg 构造函数,那么这意味着您的 3 arg 构造函数中没有其中一种类型的 bean。

【讨论】:

  • 这告诉我“永远不要使用autowire=constructor”如果有多个构造函数:) 并且由于将来可以添加更多构造函数并且xml被遗忘,只是“永远不要使用autowire=constructor
【解决方案2】:

更确切地说,下面的例子可以帮助你理解,所以我有一个 Employee 类,它与资格和地址有关系,并且 bean 在 xml 声明中可用。

<bean id="qualification" class="com.Autowiring.constructor.Qualification">
    <property name="highestQualification" value="BTech"/>
    <property name="certifcations" value="SCJP"/>
</bean>

<bean name="address" class="com.Autowiring.constructor.Address">
    <property name="city" value="Bangalore" />
    <property name="zip" value="560054" />
    <property name="building" value="Building One" />
</bean>

我们有 4 个构造函数,第一个接受两个参数,即地址和资格,第二个接受资格,第三个构造函数接受地址,然后第四个接受从 id、name、dob、地址和资格开始的所有字段。

//构造函数 - 1

public Employee(Address address, Qualification qualification) {
    super();
    System.out.println(1);
    this.address = address;
    this.qualification = qualification;
}

//构造函数 - 2

public Employee(Qualification qualification) {
    super();
    System.out.println(2);
    this.qualification = qualification;
}

//构造函数 - 3

public Employee(Address address) {
    super();
    System.out.println(3);
    this.address = address;
}

//构造函数 - 4

public Employee(int id, String name, Date dob, Address address,
        Qualification qualification) {

    super();
    System.out.println(4);
    this.id = id;
    this.name = name;
    this.dob = dob;
    this.address = address;
    this.qualification = qualification;
}

案例 1:假设没有声明构造函数 1 和 4,并且我们在员工 bean 声明中没有构造函数参数。

行为:如果我们更改构造函数的定义顺序,即将构造函数 2 的位置与 3 交换,构造函数 3 将被称为最后一个声明的构造函数。

案例 2:假设没有声明构造函数 4,并且我们在员工 bean 声明中没有构造函数参数。

行为:在这种情况下将调用构造函数 1,因为它可以获得 bean 声明中可用的类型 Qualification 和 Address,因此这满足构造函数 1 的匹配参数的条件。

案例 3:假设我们在员工 bean 声明中没有构造函数参数。

行为:在这种情况下,构造函数 1 也会被调用,因为它可以获得 bean 声明中可用的类型 Qualification 和 Address,因此这满足构造函数 1 的匹配参数的条件,但它不能调用第 4 个构造函数,因为 bean 声明文件中没有 id、name 和 dob,因此第 1 个构造函数是最佳匹配构造函数,因为我们在 bean 声明中提供了 Qualification 和 Address。

案例 4:假设我们在员工 bean 声明中有构造函数参数,并且所有构造函数都可用。

行为:它将能够调用第 4 个构造函数,因为 bean 声明文件中提供了 id、name、dob、资格和地址,因此第 3 个参数将来自构造函数 arg 和最后一个两个将来自 bean 本身的声明,因此来自第 4 个构造函数的所有参数都匹配,因此将调用第 4 个构造函数。 结论:因此案例和行为表明,在多个构造函数的情况下,spring容器尝试验证所有依赖属性并根据构造函数中可用于创建对象的所有可用属性进行验证,其中最大可能的属性可以被初始化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多