Разрешение аргумента конструктора
Я недавно начал работать над 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 ответа:
Spring использует экземпляр
ConstructorResolver
, чтобы решить, какой конструктор использовать для создания экземпляра класса. Он вызывает методautowireConstructor()
, чтобы определить это. Вы можете найти исходный код в интернете. Более старая версия, здесь . Если у вас есть исходный код (используйте maven), вы можете отладить и пройти через него самостоятельно.Внутри метода он пытается определить разницу между указанными аргументами и аргументами в контроллере с помощью метода
Это значение сравнивается со значениемArgumentsHolder#getTypeDifferenceWeight()
. В нашем случае он вернет значение0
потому что аргументы совпадают (даже в другом порядке).minTypeDiffWeight
(ПервоначальноInteger.MAX_VALUE
). Если он меньше, то текущий вычисляемый конструктор получает приоритет и значение заменяетminTypeDiffWeight
. Метод продолжается таким образом через все конструкторы класса, сравнивая снова vsminTypeDiffWeight
. Поскольку оба конструктора дадут значение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 Вы можете фактически указать имя параметра, на который ссылаетесь, чтобы устранить всю двусмысленность, поэтому, если вы не можете использовать тип и индекс вместе, это ваше решение.