2013-08-23 3 views
3

저는 최근에 봄 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은 type 속성을 전달할 때 호출 할 생성자를 결정하는 방법은 무엇입니까?

답변

6

스프링은 ConstructorResolver 인스턴스를 사용하여 클래스를 인스턴스화하는 데 사용할 생성자를 결정합니다. 이를 확인하기 위해 autowireConstructor() 메서드를 호출합니다. 소스 코드는 온라인에서 찾을 수 있습니다. 이전 버전은 here입니다. 소스가 있다면 (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() 방법 자바 독 정렬되지 않은 리턴 배열

요소를 명시하고 특정 순서 아니다.

그래서 우연의 일치입니다. 인수 유형이 일치하기 때문에 Spring은 해당 배열에서 찾은 첫 번째 생성자를 선택합니다.

+0

이런 상세한 설명을 주셔서 감사합니다 Sotirios. 첫 번째 시나리오에서도 위의 프로세스가 수행됩니까? 동일한 프로세스가 수행되면 첫 번째 시나리오에서 첫 번째 생성자를 호출 한 이유는 무엇입니까? – Beast

+1

@Beast 과정은 동일하지만 여기서는 매개 변수의 순서가 중요합니다. 'ConstructorResolver'는 생성자들의 배열을 따라 가며'(int, String)'을 사용하려하지만'Jinesh' 값을'int'로 변환 할 수 없기 때문에 실패합니다. 'UnsatisfiedDependencyException'이 발생하고 생성자를 건너 뜁니다. 배열의 두 번째 생성자가 후보가되고 (예제에서는 첫 번째)'' "77"'이 'int'로 변환 될 수 있기 때문에 선택됩니다. 스택 아래 어딘가에 변환 시스템이 있습니다. –

+0

replyour help와 모든 도움을 주셔서 감사합니다. 마지막 질문은 maven을 통해 스프링 소스 코드를 통해 디버그하고 싶다면 사용할 수있는 구성 문서가 있습니까? – Beast

1

인덱스 속성을 추가하여 생성자 인수의 순서를 명시 적으로 지정할 수 있습니다.

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

나는 당신이 인덱스를 포함하고 spring reference docs 명시 적으로하지 않습니다 당신이 할 수있는 말을하지만 함께 입력 할 수 있습니다 가정합니다.

스프링 3을 사용하면 실제로 참조하는 매개 변수의 이름을 지정할 수 있습니다. 즉, 모호성을 제거하기 위해 유형과 색인을 함께 사용할 수없는 경우 이것이 해결책입니다.

+2

처음에는 매개 변수 이름에 대한 의문점이있었습니다. 반사가 가능하지 않았기 때문입니다. 내가 가서 살펴 보았고 Spring은 바이트 코드 분석을 사용하여 매개 변수의 이름을 검색하는 멋진 마술을 수행한다. –