我最近开始在3.2版本上工作。我试图理解构造函数参数解析,以防何时通过构造函数注入传递依赖项。我创建了以下示例。
package com.springinaction.springidol;
public interface Performer {
void perform();
}
package com.springinaction.springidol;
public class Juggler implements Performer {
private int beanBags=3;
private String name;
public Juggler(){
}
public Juggler(String name,int beanBags){
System.out.println("First constructor gets called");
this.beanBags=beanBags;
this.name=name;
}
public Juggler(int beanBags,String name){
System.out.println("Second constructor gets called");
this.beanBags=beanBags;
this.name=name;
}
public void perform(){
System.out.println("JUGGLING "+beanBags+name+" BEANBAGS");
}
}
请查看下面我使用过的弹簧配置文件的实例。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="duke" class="com.springinaction.springidol.Juggler">
<constructor-arg value="Jinesh" />
<constructor-arg value="77" />
</bean>
在上面的场景中,调用的构造函数是第一个构造函数。但之后我稍微更改了xml文件,并为两个参数添加了type属性。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="duke" class="com.springinaction.springidol.Juggler">
<constructor-arg type="java.lang.String" value="Jinesh" />
<constructor-arg type="int" value="77" />
</bean>
</beans>
在上面的例子中,spring调用的构造函数是第二个构造函数。我不明白为什么spring决定调用第二个构造函数而不是第一个构造函数?在上面的例子中,当我们传递type属性时spring如何决定调用哪个构造函数?
答案 0 :(得分:6)
Spring使用ConstructorResolver
实例来解析用于实例化类的构造函数。它调用autowireConstructor()
方法来确定。您可以在线找到源代码。旧版本here。如果您有源(使用maven),您可以自己调试并完成它。
在该方法中,它尝试使用ArgumentsHolder#getTypeDifferenceWeight()
方法确定指定参数与控制器中参数之间的差异。在我们的例子中,它将返回值0
,因为参数匹配(即使是以不同的顺序)。
将该值与minTypeDiffWeight
值(最初为Integer.MAX_VALUE
)进行比较。如果它更小,则正在评估的当前构造函数将获得优先级,并且该值将替换minTypeDiffWeight
。这个方法通过所有Class'构造函数继续进行,再次与minTypeDiffWeight
进行比较。由于两个构造函数都将赋值0
(0不小于0),因此使用了第一个构造函数。
恰好发生了
Juggler.class.getDeclaredConstructors();
返回类似
的数组[public Test.Juggler(int,java.lang.String), public Test.Juggler(java.lang.String,int), public Test.Juggler()]
第一个出现第二个(声明的)构造函数。 getDeclaredConstructors()
方法javadoc状态
返回的数组中的元素没有排序,也没有排序 特别的顺序。
所以这只是巧合。因为参数类型匹配,所以Spring选择它在该数组中找到的第一个构造函数。
答案 1 :(得分:1)
您可以通过添加索引属性来显式指定构造函数参数的顺序。
<constructor-arg type="java.lang.String" index="0" value="Jinesh" />
<constructor-arg type="int" index="1" value="77" />
我假设您可以将索引和类型包括在一起,尽管spring reference docs没有明确说明您可以。
使用Spring 3,您实际上可以指定您所引用的参数的名称 - 以消除所有歧义 - 因此,如果您不能同时使用类型和索引,那么这就是您的解决方案。