在 child 未实现所有构造函数时实例化基 class

Instantiate base class when child does not implement all constructors

考虑一个简单的 bean:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class A {
    public A(Integer a){}
    public A(String a){}
}

有了 BeanFactory 的实例,我可以创建 A 个实例:

beanFactory.getBean(A.class, 1); //  using A(Integer)
beanFactory.getBean(A.class, "1"); //  using A(String)

现在,我想要一个 A 的子class,它使用所提供的两个构造函数之一。我的 class 层次结构现在变为:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Primary
public class A {
    public A(Integer a) {}
    public A(String a) {}
}

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class A1 extends A {
    public A1() { super(1); }
}

我希望这些现在可以工作:

beanFactory.getBean(A.class, 1); // using A(Integer)
beanFactory.getBean(A.class, "1"); // using A(String)
beanFactory.getBean(A1.class); // using the A1()

但是,前两个调用失败

org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'A1' defined in file [...]: Could not resolve matching constructor 
(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)

请注意,我并没有尝试使用 this question 的作者等参数来创建子 class。

另请注意,如果我定义(无用的)A1(Integer)A1(String) 构造函数,Spring 不会再抱怨了。

使用Spring 4.2.2.RELEASE.

为什么当我定义了一些 child 时,bean factory 不能用它的构造函数创建基础 class 实例?

请找一个单元测试重现它in Github repo

此行为的原因是:Spring不要使用构造函数参数来确定要实例化的适当 bean 类型。 (或者,换句话说:它只使用构造函数参数来解析要使用的正确构造函数)

我们只考虑这一行beanFactory.getBean(A.class, 1);

bean 解析如下:

  1. 确定所有请求类型的bean。在您的情况下:有 2 种可能的 bean:A 或 A1(均为 A 类型)

  2. 为第 1 步中找到的每种可能类型创建一个实例 ,并根据给定的参数 使用最合适的构造函数来实现。在您的情况下,使用带有 Integer 的构造函数实例化一个 A 和一个 A1。 (旁注:我们在这里谈论 prototype beans。对于 singleton beans :当且仅当它还没有创建新实例时存在)

  3. 在第 2 步的所有实例化 bean 中查找 @Primary(如果找到 return 它)

  4. 在步骤 2 的所有实例化 bean 中寻找优先级最高的 bean(如果找到 return 它)

  5. 扔一个"no unique bean exception"

在您的情况下:当尝试使用一个 Integer 参数实例化 A1 类型的 bean 时,算法在第 2 步失败。

当您定义 A1(String)A1(Integer) 时:算法不会在第 2 步失败,因此转到第 3 步并解析类型,因为 class 上的 @Primary答.

Source code is here。仔细查看此处描述的算法的第 353 --> 366 行。


我只能猜测这种行为的原因,但这可能是因为您可以为构造函数参数指定默认值,因此:构造函数参数(传递给 getBean(Class, args...) )不是消除 bean 歧义的有效线索类型。