3

我最近开始研究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");
    }
}

请在下面找到我使用过的 spring 配置文件的实例。

<?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 如何决定调用哪个构造函数?

4

2 回答 2

6

Spring 使用ConstructorResolver实例来解析使用哪个构造函数来实例化您的类。它调用autowireConstructor()方法来确定。你可以在网上找到源代码。旧版本,在这里。如果你有源代码(使用 maven),你可以自己调试和浏览它。

在该方法中,它尝试使用方法确定指定参数与控制器中的参数之间的差异ArgumentsHolder#getTypeDifferenceWeight()。在我们的例子中,它将返回一个值,0因为参数匹配(即使顺序不同)。

该值与一个minTypeDiffWeight值(最初是Integer.MAX_VALUE)进行比较。如果它更小,则正在评估的当前构造函数获得优先级,并且值替换minTypeDiffWeight. 该方法通过所有类的构造函数继续这样,再次比较与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 选择它在该数组中找到的第一个构造函数。

于 2013-08-23T01:38:49.827 回答
1

您可以通过添加索引属性显式指定构造函数参数的顺序。

<constructor-arg type="java.lang.String" index="0" value="Jinesh" />
<constructor-arg type="int" index="1" value="77" />

我假设您可以将 index 和 type 一起包含,尽管spring 参考文档没有明确说明您可以。

使用 Spring 3,您实际上可以指定您所指的参数的名称 - 以消除所有歧义 - 因此,如果您不能同时使用类型和索引,这就是您的解决方案。

于 2013-08-23T07:34:06.317 回答