构造函数参数解析

时间:2013-08-23 01:20:10

标签: java spring

我最近开始在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如何决定调用哪个构造函数?

2 个答案:

答案 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,您实际上可以指定您所引用的参数的名称 - 以消除所有歧义 - 因此,如果您不能同时使用类型和索引,那么这就是您的解决方案。