Spring構造方法注入型別歧義


在Spring框架中,當一個類包含多個建構函式帶的引數相同,它總是會造成建構函式注入引數型別歧義的問題。

問題

讓我們來看看這個客戶 bean 範例。它包含兩個構造方法,均接受3個不同的資料型別引數。
package com.tw511.common;

public class Customer 
{
	private String name;
	private String address;
	private int age;
	
	public Customer(String name, String address, int age) {
		this.name = name;
		this.address = address;
		this.age = age;
	}
	
	public Customer(String name, int age, String address) {
		this.name = name;
		this.age = age;
		this.address = address;
	}
	//getter and setter methods
	public String toString(){
		return " name : " +name + "\n address : "
               + address + "\n age : " + age;
	}

}
在Spring bean 的組態檔案中,通過傳遞一個「yiibai' 的名字,地址為'188',以及年齡為'28'。
<!--Spring-Customer.xml-->
<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-2.5.xsd">

	<bean id="CustomerBean" class="com.tw511.common.Customer">

		<constructor-arg>
			<value>yiibai</value>
		</constructor-arg>
		
		<constructor-arg>
			<value>188</value>
		</constructor-arg>
		
		<constructor-arg>
			<value>28</value>
		</constructor-arg>
        </bean>

</beans>
執行它,你期望的結果是什麼?
package com.tw511.common;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App 
{
    public static void main( String[] args )
    {
    	ApplicationContext context = 
    	  new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});

    	Customer cust = (Customer)context.getBean("CustomerBean");
    	System.out.println(cust);
    }
}

輸出結果

name : yiibai
 address : 28
 age : 188
其結果不是我們所期望的,第一個構造器不執行,而是第二建構函式執行。在Spring引數型別'188' 能夠轉換成int,所以Spring只是轉換它,並採用第二個構造來執行,即使你認為它應該是一個字串。
另外,如果Spring不能解決使用哪個建構函式,它會提示以下錯誤資訊
constructor arguments specified but no matching constructor 
found in bean 'CustomerBean' (hint: specify index and/or 
type arguments for simple parameters to avoid type ambiguities)

解決

為了解決這個問題,應該為建構函式指定的確切資料型別,通過像這樣型別的屬性:
<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-2.5.xsd">

	<bean id="CustomerBean" class="com.tw511.common.Customer">
	
		<constructor-arg type="java.lang.String">
			<value>yiibai</value>
		</constructor-arg>
		
		<constructor-arg type="java.lang.String">
			<value>188</value>
		</constructor-arg>
		
		<constructor-arg type="int">
			<value>28</value>
		</constructor-arg>
		
	</bean>

</beans>
再次執行它,現在得到你所期望的。
輸出結果
name : yiibai
 address : 188
 age : 28

這是一個很好的做法,顯式宣告每個建構函式引數的資料型別,以避免上述構造注入型歧義的問題。