2013-08-23 144 views
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屬性時調用哪個構造函數?

回答

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選擇它在該數組中找到的第一個構造函數。

+0

感謝這樣詳細的解釋索蒂里奧斯。第一種情況下是否也遵循上述流程?如果遵循相同的流程,那麼爲什麼它在第一個場景中調用了第一個構造函數? – Beast

+1

@Beast過程是一樣的,但這裏參數的順序很重要。在'ConstructorResolver'遍歷構造的陣列中,嘗試使用'(INT,字符串)'但失敗了,因爲值'Jinesh'不能轉換到一個'int'。發生'UnsatisfiedDependencyException'並且該構造函數被跳過。所述陣列中的第二個構造變成候選(第一在您的示例),並且因爲'「77」'可以被轉換爲一個'int',它被選擇。在堆棧的某個地方,有一個轉換系統在做某些事情。 –

+0

感謝您的replyour的幫助,如果我想通過基於Maven春源代碼你們有任何配置文件來調試所有help.One最後一個問題? – Beast

1

您可以通過添加索引屬性來顯式指定構造函數參數的排序。

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

我想你可以包括指數雖然spring reference docs沒有明確說你可以鍵入在一起。

使用Spring 3實際上你可以指定你指的是參數的名稱 - 刪除所有不確定性 - 如果你不能使用類型和索引在一起,這是你的解決方案。

+2

起初,我有我的有關參數名的事情的疑惑,因爲這是不可能與反思。我去看了看,Spring用字節代碼分析來做一些很酷的魔法來檢索參數的名字。 –