Spring構造方法注入類型歧義

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

問題

讓我們來看看這個客戶 bean 實例。它包含兩個構造方法,均接受3個不同的數據類型參數。

package com.yiibai.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'。

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

    <constructor-arg>
        <value>yiibai</value>
    </constructor-arg>

    <constructor-arg>
        <value>188</value>
    </constructor-arg>

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

運行它,你期望的結果是什麼?

package com.yiibai.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)

解決

爲了解決這個問題,應該爲構造函數指定的確切數據類型,通過像這樣類型的屬性:

<bean id="CustomerBean" class="com.yiibai.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>

再次運行它,現在得到你所期望的。

輸出結果

name : yiibai
address : 188
age : 28

這是一個很好的做法,顯式聲明每個構造函數參數的數據類型,以避免上述構造注入型歧義的問題。