考虑一个简单的 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
的子类,它使用提供的两个构造函数之一。我的类层次结构现在变成:
@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 的作者这样的参数创建子类。 .
另请注意,如果我定义(无用的)A1(Integer)
和 A1(String)
构造函数,Spring 不会再提示。
使用 Spring 4.2.2.RELEASE。
为什么当我定义一些子项时,bean 工厂无法使用其构造函数创建基类实例?
请找到一个重现它的单元测试 in Github repo .
最佳答案
此行为的原因是:Spring 不使用构造函数参数来确定要实例化的适当 bean 类型。 (或者,换句话说:它只使用构造函数参数来解析要使用的正确构造函数)
我们只考虑这一行 beanFactory.getBean(A.class, 1);
bean 分辨率如下:
确定具有请求类型的所有 bean。在你的情况下:有2种可能的bean:A或A1(两者都是A类型)
为第 1 步中找到的每种可能类型创建一个实例,并根据给定参数使用最合适的构造函数。在您的情况下,使用带有整数的构造函数实例化一个 A 和一个 A1。 (旁注:我们在这里讨论的是原型(prototype)bean。对于单例bean:当且仅当它尚不存在时才会创建一个新实例)
在第 2 步中在所有实例化 bean 中查找 @Primary(如果找到则返回)
在步骤 2 中查找所有实例化 Bean 中优先级最高的 Bean(如果找到则返回)
抛出“无唯一 bean 异常”
在您的情况下:当尝试使用一个整数参数实例化 A1 类型的 bean 时,算法在第 2 步失败。
当您定义 A1(String)
和 A1(Integer)
时:算法在步骤 2 中不会失败,因此会转到步骤 3 并解析类型,因为A 类上的 @Primary。
Source code is here 。仔细查看第 353 行 --> 366 行,了解此处描述的算法。
我只能猜测这种行为的原因,但这可能是因为您可以为构造函数参数指定默认值,因此:构造函数参数(传递给 getBean(Class, args...)
)不是消除 Bean 类型歧义的有效线索。
关于java - 当子类未实现所有构造函数时实例化基类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34565344/