1. 程式人生 > >Spring重溫(三)--Spring依賴註入(DI)

Spring重溫(三)--Spring依賴註入(DI)

igui 顯式 -a framework 聲明 構造 問題 ram cif

前言:在Spring框架中,DI(依賴註入)是用來定義對象彼此間的依賴,主要有set方法註入和構造器註入兩種方式。另外,當一個類包含多個構造函數帶的參數相同,它總是會造成構造函數註入參數類型歧義的問題,我會在第3點進行介紹並給出解決方案。

1.setter方法註入:

package com.yiibai.output;

import com.yiibai.output.IOutputGenerator;

public class OutputHelper
{
    IOutputGenerator outputGenerator;
    
    public void setOutputGenerator(IOutputGenerator outputGenerator){
        
this.outputGenerator = outputGenerator; } }

一個 bean 配置文件用來聲明bean 和通過 setter 設置註入(property標簽)的依賴。

<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="OutputHelper" class="com.yiibai.output.OutputHelper"> <property name="outputGenerator"> <ref bean="CsvOutputGenerator" /> </property> </bean> <bean id="CsvOutputGenerator" class="com.yiibai.output.impl.CsvOutputGenerator" /> </beans>

2.構造器註入:

例子:

package com.yiibai.output;

import com.yiibai.output.IOutputGenerator;

public class OutputHelper
{
    IOutputGenerator outputGenerator;
    
        OutputHelper(IOutputGenerator outputGenerator){
        this.outputGenerator = outputGenerator;
    }
}

bean 配置文件來聲明bean並通過構造函數(constructor-arg標簽)設置註入依賴

<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="OutputHelper" class="com.yiibai.output.OutputHelper">
        <constructor-arg>
            <bean class="com.yiibai.output.impl.CsvOutputGenerator" />
        </constructor-arg>
    </bean>
    
<bean id="CsvOutputGenerator" class="com.yiibai.output.impl.CsvOutputGenerator" />
        
</beans>

3.當一個類包含多個構造函數帶的參數相同,它總是會造成構造函數註入參數類型歧義的問題。

讓我們來看看這個客戶 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‘。

<!--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.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>

</beans>

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

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

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

<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.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>

</beans>

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

name : yiibai
 address : 188
 age

總結:在依賴註入中,主要有seter方法註入和構造函數註入兩種方式,其中setter方法註入是在xml配置文件中通過property設置依賴,而構造器通過constructor-arg設置依賴;

顯式聲明每個構造函數參數的數據類型,可以避免上述構造註入型歧義的問題。

Spring重溫(三)--Spring依賴註入(DI)