閱讀379 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《Spring攻略(第2版)》——1.4 解決構造程序歧義

本節書摘來自異步社區《Spring攻略(第2版)》一書中的第1章,第1.4節,作者: 【美】Gary Mak , Josh Long , Daniel Rubio著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看

1.4 解決構造程序歧義

1.4.1 問題
當你為Bean指定一個或者多個構造程序參數時,Spring將試圖在Bean類中查找對應的構造程序,並且傳遞用於Bean實例化的參數。但是,如果你的參數可以應用到超過一個構造程序,可能在構造程序匹配中造成歧義。在這種情況下,Spring可能無法調用你所預期的構造程序。

1.4.2 解決方案
你可以為元素指定type和index屬性,幫助Spring查找預期的構造程序。

1.4.3 工作原理
現在添加一個新的構造程序到SequenceGenerator類,參數為prefix和suffix。

package com.apress.springrecipes.sequence;

public class SequenceGenerator {
   ...
   public SequenceGenerator(String prefix, String suffix) {
     this.prefix = prefix;
     this.suffix = suffix;
   }
}

在Bean聲明中,你可以通過元素指定一個或者多個構造程序參數。Spring將嚐試為該類尋找合適的構造程序,並傳遞用於Bean實例化的參數。回憶一下,中沒有name屬性,因為構造程序參數是基於位置的。

<bean 
   >
   <constructor-arg value="30" />
   <constructor-arg value="A" />
   <property name="initial" value="100000" />
</bean>

Spring很容易為這兩個參數找到一個構造程序,因為隻有一個構造程序需要兩個參數。假定你必須為SequenceGenerator添加另一個具有prefix和initial參數的構造程序。

package com.apress.springrecipes.sequence;

public class SequenceGenerator {
   ...
   public SequenceGenerator(String prefix, String suffix) {
     this.prefix = prefix;
     this.suffix = suffix;
   }

   public SequenceGenerator(String prefix, int initial) {
     this.prefix = prefix;
     this.initial = initial;
   }
}

為了調用這個構造程序,你建立下麵的Bean聲明,傳遞一個前綴和一個初始值。剩下的後綴通過設值方法注入。

<bean 
   >
   <constructor-arg value="30" />
   <constructor-arg value="100000" />
   <property name="suffix" value="A" />
</bean>

但是,如果你現在運行應用程序,將會得到如下結果:

300A

301A

這個意外結果的起因是調用了第一個帶有prefix和suffix參數的構造程序,而不是第二個。這是因為Spring默認將兩個參數都解析為String類型,第一個構造程序不需要類型轉換,所以被認定為最合適的。為了指定參數的預期類型,你必須設置中的type屬性。

<bean 
   >
   <constructor-arg type="java.lang.String" value="30" />
   <constructor-arg type="int" value="100000" />
   <property name="suffix" value="A" />
</bean>

現在,再為SequenceGenerator添加一個帶有initial和suffix參數的構造程序,並相應修改Bean聲明。

package com.apress.springrecipes.sequence;
public class SequenceGenerator {
   ...
   public SequenceGenerator(String prefix, String suffix) {
     this.prefix = prefix;
     this.suffix = suffix;
   }

   public SequenceGenerator(String prefix, int initial) {
     this.prefix = prefix;
     this.initial = initial;
   }

   public SequenceGenerator(int initial, String suffix) {
     this.initial = initial;
     this.suffix = suffix;
   }
}

<bean 
   >
   <constructor-arg type="int" value="100000" />
   <constructor-arg type="java.lang.String" value="A" />
   <property name="prefix" value="30" />
</bean>

如果你再次運行應用程序,可能得到正確的結果,或者得到下列意外的結果:

30100000null

30100001null

這種不確定性的起因是Spring在內部對每個構造程序與參數的兼容性評分。但是在這個評分過程中,沒有考慮參數出現在XML中的順序。這意味著從Spring的角度看,第二個和第三個構造程序將得到同樣的分數。選擇哪一個構造程序取決於匹配的順序。根據Java Reflection API,更精確地說是Class.getDeclaredConstructors()方法,返回的構造程序將是任意順序的,可能與聲明的順序不同。所有這些因素綜合起來,導致了構造程序匹配中的歧義。

為了避免這個問題,你必須通過的index屬性明確指出參數的索引值。設置了type和index屬性,Spring就能夠準確地為Bean找到預期的構造程序。

<bean 
   >
   <constructor-arg type="int" index="0" value="100000" />
   <constructor-arg type="java.lang.String" index="1" value="A" />
   <property name="prefix" value="30" />
</bean>

但是,如果你相當確定構造程序不會導致歧義,就可以忽略type和index屬性。

最後更新:2017-05-31 15:01:40

  上一篇:go  《Spring攻略(第2版)》——1.5 指定Bean引用
  下一篇:go  結合案例深入解析orphan socket產生與消亡(一)