Разрешение аргумента конструктора


Я недавно начал работать над 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 решил вызвать второй конструктор вместо первого? В случаях, подобных приведенным выше, как spring решает, какой конструктор вызывать, когда мы передаем атрибут type ?

2   3  

2 ответа:

Spring использует экземпляр ConstructorResolver, чтобы решить, какой конструктор использовать для создания экземпляра класса. Он вызывает метод autowireConstructor(), чтобы определить это. Вы можете найти исходный код в интернете. Более старая версия, здесь . Если у вас есть исходный код (используйте maven), вы можете отладить и пройти через него самостоятельно.

Внутри метода он пытается определить разницу между указанными аргументами и аргументами в контроллере с помощью метода ArgumentsHolder#getTypeDifferenceWeight(). В нашем случае он вернет значение 0 потому что аргументы совпадают (даже в другом порядке).

Это значение сравнивается со значением minTypeDiffWeight (Первоначально Integer.MAX_VALUE). Если он меньше, то текущий вычисляемый конструктор получает приоритет и значение заменяет minTypeDiffWeight. Метод продолжается таким образом через все конструкторы класса, сравнивая снова vs 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 выбирает первый конструктор, который он находит в этом массиве.

Вы можете явно указать порядок аргументов конструктора, добавив атрибут index.

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

Я предполагаю, что вы можете включить индекс и тип вместе, хотяspring reference docs явно не говорят, что вы можете.

С помощью Spring 3 Вы можете фактически указать имя параметра, на который ссылаетесь, чтобы устранить всю двусмысленность, поэтому, если вы не можете использовать тип и индекс вместе, это ваше решение.