Spring系列之依賴注入的方式


一、依賴注入方式

      對於spring配置一個bean時,如果需要給該bean提供一些初始化參數,則需要通過依賴注入方式,所謂的依賴注入就是通過spring將bean所需要的一些參數傳遞到bean實例對象的過程,spring的依賴注入有3種方式:

·使用屬性的setter方法注入 ,這是最常用的方式;
·使用構造器注入;
·使用Filed注入(用於注解方式)。

1.使用屬性注入

     屬性注入即通過setXxx()方法注入Bean的屬性值或依賴對象,由於屬性注入方式具有可選擇性和靈活性高的優點,因此屬性注入是實際應用中最常采用的注入方式。

<bean id=”……” class=”……”>  
    <property name=”屬性1” value=”……”/>  
    <property name=”屬性2” value=”……”/>  
    ……  
</bean>  

      屬性注入要求Bean提供一個默認的構造函數,並為需要注入的屬性提供對應的Setter方法。Spring先調用Bean的默認構造函數實例化Bean對象,然后通過反射的方式調用Setter方法注入屬性值。來看一個簡單的例子。

package com.spring.model;

public class Car {
    
    private int maxSpeed;
    private String brand;
    private double price;
    
    public int getMaxSpeed() {
        return maxSpeed;
    }
    //一定要寫被注入對象的set方法
    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    
    public void run(){
        System.out.println("brand:"+brand+",maxSpeed:"+maxSpeed+",price:"+price);
    }
}

     Car類中定義了3個屬性,並分別提供了對應的Setter方法。(注:默認構造函數是不帶參的構造函數。Java語言規定如果類中沒有定義任何構造函數,則JVM自動為其生成一個默認的構造函數。反之,如果類中顯示定義了構造函數,則JVM不會為其生成默認的構造函數。所以假設Car類中顯示定義了一個帶參的構造函數,如public Car(String brand),則需要同時提供一個默認構造函數public Car(),否則使用屬性注入時將拋出異常。
下面在Spring配置文件中對Car進行屬性注入:

<!-- 屬性注入 -->
<bean id="car" class="com.spring.model.Car">  
    <property name="maxSpeed" value="200"></property>
    <property name="brand" value="紅旗CA72"></property>  
    <property name="price" value="200000.00"></property>
</bean>

     在上述代碼中配置了一個Bean,並為該Bean的3個屬性提供了屬性值。具體來說,Bean的每一個屬性對應一個<property>標簽,name為屬性的名稱,在Bean實現類中擁有與其對應的Setter方法:maxSpeed對應setMaxSpeed(),brand對應setBrand()。
     需要指出的是:Spring只會檢查Bean中是否有對應的Setter方法,至於Bean中是否有對應的屬性變量則不做要求。例如配置文件中<property name="brand"/>的屬性配置項僅要求Car類中擁有setBrand()方法,但Car類不一定要擁有brand成員變量。

測試方法:

/**
 * 屬性注入
 */
@Test
public void test(){
    //讀取配置文件
    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
    //獲取bean的實例
    Car car=(Car) ctx.getBean("car");
    car.run();
}

 2.構造函數注入

構造函數注入是除屬性注入之外的另一種常用的注入方式,它保證一些必要的屬性在Bean實例化時就得到設置,並且確保了Bean實例在實例化后就可以使用。
使用方式:
第一,在類中,不用為屬性設置setter方法,但是需要生成該類帶參的構造方法。
第二,在配置文件中配置該類的bean,並配置構造器,在配置構造器中用到了<constructor-arg>節點,該節點有四個屬性:
· index是索引,指定注入的屬性,從0開始;
· type是指該屬性所對應的類型;
· ref 是指引用的依賴對象;
· value 當注入的不是依賴對象,而是基本數據類型時,就用value;

(1)按類型匹配入參

      如果任何可用的Car對象都必須提供maxSpeed、brand和price的值,使用屬性注入方式只能人為在配置時提供保證,而無法在語法級提供保證,這時通過構造函數注入就可以很好地滿足這一要求。使用構造函數注入的前提是Bean必須提供帶參的構造函數,下面為Car提供一個可設置maxSpeed、brand和price屬性的構造函數。

package com.spring.model;

public class Car {
    
    private int maxSpeed;
    private String brand;
    private double price;
    
    //帶參構造方法
    public Car(int maxSpeed,String brand, double price){
        this.maxSpeed=maxSpeed;
        this.brand=brand;
        this.price=price;
    }
    
    public void run(){
        System.out.println("brand:"+brand+",maxSpeed:"+maxSpeed+",price:"+price);
    }
}

構造函數注入的配置方式和屬性注入方式的配置有所不同,在spring配置文件中使用構造函數注入裝配這個Car Bean。

<!-- 構造函數注入(按類型匹配) -->
<bean id="car1" class="com.spring.model.Car">  
    <constructor-arg type="int" value="300"></constructor-arg>
    <constructor-arg type="java.lang.String" value="寶馬"></constructor-arg>
    <constructor-arg type="double" value="300000.00"></constructor-arg>
</bean>

在<constructor-arg>的元素中有一個type屬性,它表示構造函數中參數的類型,為spring提供了判斷配置項和構造函數入參對應關系的“信息”。

(2)按索引匹配入參

      我們知道,Java語言通過入參的類型及順序區分不同的重載方法,對於上面代碼中的Car類,Spring僅通過type屬性指定的參數類型就可以知道“寶馬”對應String類型的brand入參,而“300000.00”對應double類型的price入參。但是,如果Car構造函數3個入參的類型相同,僅通過type就無法確定對應關系了,這時需要通過入參索引的方式進行確定。
為了更好地演示按索引匹配入參的配置方式,特意對Car構造函數進行一下調整。

public Car(String brand, String corp,double price){
    this.brand=brand;
    this.corp=corp;
    this.price=price;
}

brand和corp的入參類型都是String,所以String將無法確定type為String的<constructor-arg>到底對應的是brand還是corp。但是,通過顯示指定參數的索引能夠消除這種不確定性,如下所示。

<!-- 構造函數注入(按索引匹配) -->
<bean id="car2" class="com.spring.model.Car"> 
    <!-- 注意索引從0開始 --> 
    <constructor-arg index="0" value="寶馬"></constructor-arg>
    <constructor-arg index="1" value="中國一汽"></constructor-arg>
    <constructor-arg index="2" value="300000.00"></constructor-arg>
</bean>

構造函數第一個參數索引為0,第二個為1,以此類推,因此很容易知道“寶馬”對應brand入參,而“中國一汽”對應corp入參。

(3)聯合使用類型和索引匹配入參
     有時需要聯合使用type和index才能確定匹配項和構造函數入參的對應關系,看下面的代碼。

public Car(String brand, String corp,double price){
    this.brand=brand;
    this.corp=corp;
    this.price=price;
}

public Car(String brand, String corp,int maxSpeed){
    this.brand=brand;
    this.corp=corp;
    this.maxSpeed=maxSpeed;
}

     這里,Car擁有兩個重載的構造函數,它們都有三個入參。針對這種情況,按照入參索引的配置方式又難以滿足要求了,這時需要聯合使用<constructor-arg>的type和index才能解決問題,看下面代碼。

<!-- 構造函數注入(通過入參類型和位置索引確定對應關系) -->
<!-- 對應public Car(String brand, String corp,int maxSpeed)構造函數 -->
<bean id="car3" class="com.spring.model.Car">  
    <constructor-arg index="0" type="java.lang.String" value="奔馳"></constructor-arg>
    <constructor-arg index="1" type="java.lang.String" value="中國一汽"></constructor-arg>
    <constructor-arg index="2" type="int" value="200"></constructor-arg>
</bean>

      對於上面的兩個構造函數,如果僅通過index進行配置,Spring將無法確定第3個入參配置項究竟是對應int的maxSpeed還是double的price,采用索引匹配時,真正引起歧義的地方在於第3個入參,因此僅需要明確指定第3個入參的類型就可以取消歧義了。所以在上面的代碼中,第1個和第2個<constructor-arg>元素的type屬性可以去除。
      對於由於參數數目相同而類型不同所引起的潛在配置歧義問題,Spring容器可以正確啟動且不會給出報錯信息,它將隨機采用一個匹配的構造函數實例化Bean,而被選擇的構造函數可能並不是用戶所希望的。因此,必須特別謹慎,以避免潛在的錯誤。

 3.使用字段(Filed)注入(用於注解方式)

除了上面講到的使用屬性的setter方法或使用構造器方法來注入依賴對象,還有一種注入依賴對象的方法,就是使用注解。

來看一個例子,首先不使用注解的方式。

新建一個業務接口:

package com.spring.service;

public interface ICommonService {
    
    public void add();
}

實現類:

package com.spring.service.impl;

import com.spring.dao.ICommonDao;
import com.spring.service.ICommonService;

public class CommonServiceImpl implements ICommonService{
    
    private ICommonDao commonDao;
    
    // 依賴注入DAO組件所需的setter方法
    public void setCommonDao(ICommonDao commonDao) {
        this.commonDao = commonDao;
    }
    
    public void add(){
        commonDao.add();
    }
}

dao層接口:

package com.spring.dao;

public interface ICommonDao {
    public void add();
}

實現類:

package com.spring.dao.impl;

import com.spring.dao.ICommonDao;

public class CommonDaoImpl implements ICommonDao{
    
    public void add(){
        System.out.println("enter add!");
    }
}

配置文件:

<bean id="commonDao" class="com.spring.dao.impl.CommonDaoImpl"></bean>
<bean id="commonService" class="com.spring.service.impl.CommonServiceImpl">
    <!-- 注入持久化訪問所需的DAO組件 -->
    <property name="commonDao" ref="commonDao"/>
</bean>

以上是不使用注解的方式注入依賴對象(使用屬性注入),下面來看一下使用注解為某個bean注入依賴對象。

(1)首先,在Spring容器的配置文件applicationContext.Xml文件中配置以下信息,該信心是一個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"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"     xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd     ">
    
</beans>

注意:只有配置了紫色部分的行才可以引入注解的命名空間,否則報錯。以上的配置隱式的注冊了多個對注釋進行解析的處理器:AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor等。

(2)其次,在配置文件中打開<context:annotation-config>節點,告訴Spring容器可以用注解的方式注入依賴對象;其在配置文件中的代碼如下:

<beans>

……

<context:annotation-config></context:annotation-config>

……

</beans>

(3)第三,在配置文件中配置bean對象,如下:

<bean id="commonDao" class="com.spring.dao.impl.CommonDaoImpl"></bean>
<bean id="commonService" class="com.spring.service.impl.CommonServiceImpl"></bean>

(4)第四,在需要依賴注入的類中(本例中是CommonServiceImpl),聲明一個依賴對象,不用生成該依賴對象的setter方法,並且為該對象添加注解。

 修改業務層實現類CommonServiceImpl

package com.spring.service.impl; import javax.annotation.Resource; import com.spring.dao.ICommonDao; import com.spring.service.ICommonService; public class CommonServiceImpl implements ICommonService{ @Resource(name="commonDao") private ICommonDao commonDao; // // 依賴注入DAO組件所需的setter方法 // public void setCommonDao(ICommonDao commonDao) { // this.commonDao = commonDao; // } public void add(){ commonDao.add(); } }

      其中,在Java代碼中可以使用@Autowired或@Resource注解方式進行Spring的依賴注入。兩者的區別是:@Autowired默認按類型裝配,@Resource默認按名稱裝配,當找不到與名稱匹配的bean時,才會按類型裝配。

      比如:我們用@Autowired為上面的代碼ICommonDao接口的實例對象進行注解,它會到Spring容器中去尋找與ICommonDao對象相匹配的類型,如果找到該類型則將該類型注入到commonDao字段中;

     如果用@Resource進行依賴注入,它先會根據指定的name屬性去Spring容器中尋找與該名稱匹配的類型,例如:@Resource(name="commonDao"),如果沒有找到該名稱,則會按照類型去尋找,找到之后,會對字段commonDao進行注入。

     使用注解注入依賴對象不用再在代碼中寫依賴對象的setter方法或者該類的構造方法,並且不用再配置文件中配置大量的依賴對象,使代碼更加簡潔,清晰,易於維護。

     在Spring IOC編程的實際開發中推薦使用注解的方式進行依賴注入。

二、依賴注入——自動裝配

     在應用中,我們常常使用<ref>標簽為JavaBean注入它依賴的對象,同時也Spring為我們提供了一個自動裝配的機制,在定義Bean時,<bean>標簽有一個autowire屬性,我們可以通過指定它來讓容器為受管JavaBean自動注入依賴對象。

自動裝配是在配置文件中實現的,如下:<bean id="***" class="***" autowire="byType">

只需要配置一個autowire屬性即可完成自動裝配,不用再配置文件中寫<property>,但是在類中還是要生成依賴對象的setter方法。

<bean>的autowire屬性有如下六個取值,他們的說明如下

1.No:即不啟用自動裝配。Autowire默認的值。默認情況下,需要通過"ref"來裝配bean,如下:

package com.lei.common;
 
public class Customer 
{
    private Person person;
 
    public Customer(Person person) {
        this.person = person;
    }
 
    public void setPerson(Person person) {
        this.person = person;
    }
    //...
}
package com.lei.common;
 
public class Person 
{
    //...
}

配置文件:

<bean id="customer" class="com.lei.common.Customer">
    <property name="person" ref="person" />
</bean>
<bean id="person" class="com.lei.common.Person" />

2.byName:按名稱裝配  可以根據屬性的名稱在容器中查詢與該屬性名稱相同的bean,如果沒有找到,則屬性值為null。假設Boss類中有一個名為car的屬性,如果容器中剛好有一個名為car的Bean,Spring就會自動將其裝配給Boss的car屬性。

     根據屬性Property的名字裝配bean,這種情況,Customer設置了autowire="byName",Spring會自動尋找與屬性名字“person”相同的bean,找到后,通過調用setPerson(Person person)將其注入屬性。

<bean id="customer" class="com.lei.common.Customer" autowire="byName" />
<bean id="person" class="com.lei.common.Person" />

如果根據 Property name找不到對應的bean配置,如下:

<bean id="customer" class="com.lei.common.Customer" autowire="byName" />
<bean id="person_another" class="com.lei.common.Person" />

Customer中Property名字是person,但是配置文件中找不到person,只有person_another,這時就會裝配失敗,運行后,Customer中person=null。

3.byType:按類型裝配  可以根據屬性類型,在容器中尋找該類型匹配的bean,如有多個,則會拋出異常,如果沒有找到,則屬性值為null。假設Boss類中有一個Car類型的屬性,如果容器中剛好有一個Car類型的Bean,Spring就會自動將其裝配給Boss的這個屬性。

     根據屬性Property的數據類型自動裝配,這種情況,Customer設置了autowire="byType",Spring會總動尋找與屬性類型相同的bean,找到后,通過調用setPerson(Person person)將其注入。

<bean id="customer" class="com.lei.common.Customer" autowire="byType" />
<bean id="person" class="com.lei.common.Person" />

 如果配置文件中有兩個類型相同的bean會怎樣呢?如下:

<bean id="customer" class="com.lei.common.Customer" autowire="byType" />
<bean id="person" class="com.lei.common.Person" />
<bean id="person_another" class="com.lei.common.Person" />

一旦配置如上,有兩種相同數據類型的bean被配置,將拋出UnsatisfiedDependencyException異常,見以下:
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException:
所以,一旦選擇了“byType”類型的自動裝配,請確認你的配置文件中每個數據類型定義一個唯一的bean。

4.constructor:與byType方式相似,不同之處在與它應用於構造器參數,如果在容器中沒有找到與構造器參數類型一致的bean,那么將拋出異常。(根據構造函數參數的數據類型,進行byType模式的自動裝配。)

這種情況下,Spring會尋找與參數數據類型相同的bean,通過構造函數public Customer(Person person)將其注入。

<bean id="customer" class="com.lei.common.Customer" autowire="constructor" />
<bean id="person" class="com.lei.common.Person" />

5.autodetect:通過bean類的自省機制(introspection)來決定是使用constructor還是byType的方式進行自動裝配。如果Bean有空構造器那么將采用“byType”自動裝配方式,否則使用“constructor”自動裝配方式。

這種情況下,Spring會先尋找Customer中是否有默認的構造函數,如果有相當於上邊的"constructor"這種情況,用構造函數注入,否則,用"byType"這種方式注入,所以,此例中通過調用public Customer(Person person)將其注入。

<bean id="customer" class="com.lei.common.Customer" autowire="autodetect" />
<bean id="person" class="com.lei.common.Person" />

6.default:由上級標簽<beans>的default-autowire屬性確定。

注意:在配置bean時,<bean>標簽中Autowire屬性的優先級比其上級標簽高,即是說,如果在上級標簽中定義default-autowire屬性為byName,而在<bean>中定義為byType時,Spring IoC容器會優先使用<bean>標簽的配置。

小結:使用自動裝配,配置文件簡潔了許多。但是,自動裝配並不是十全十美的,我們不論是使用byName還是byType的方法,Spring不一定就能很准確的為我們找到JavaBean依賴的對象。在這種情況下,你務必遵守javabean的命名規范,另外,如果使用自動裝配,Spring配置文件的可讀性也大大降低,我們不能很容易的看出個bean之間的依賴關系,這也在一定程度上降低了程序可維護性;也容易造成潛在的錯誤,比如說通過byName來裝配,如果將屬性 名字改了后,Spring就不會將其自動裝配給Bean的屬性了。

因此在使用自動裝配時,應當權衡利弊,合理的與ref的方法相結合,盡量在降低工作量的同時,保證應用的可維護度。但是spring的reference還是不推薦在定義中用這個功能。

不是所有類型都能自動裝配,不能自動裝配的數據類型:Object、基本數據類型(Date、CharSequence、Number、URI、URL、Class、int)等。

三、注入參數詳解

·注入常量

注入常量是依賴注入中最簡單的。配置方式如下所示:

<property name="message" value="Hello World!"/><property name="index"><value>1</value></property>

以上兩種方式都可以,從配置來看第一種更簡潔。注意此處“value”中指定的全是字符串,由Spring容器將此字符串轉換成屬性所需要的類型,如果轉換出錯,將拋出相應的異常。

·注入集合類型

Java.util包中的集合類是最常用的數據結構類型,主要包括List、Set、Map、Properties,Spring為這些集合類型屬性提供了專門的配置元素標簽。

1.List:需要使用<list>標簽來配置注入。

新建一個Boss類,並在類中添加一個List類型的favorites屬性。

package com.spring.model;

import java.util.List;

public class Boss {
    
    private List favorites;

    public List getFavorites() {
        return favorites;
    }

    public void setFavorites(List favorites) {
        this.favorites = favorites;
    }
    
    public void print(){
        System.out.println(favorites);
    }
}

對應Spring中的配置片段如下所示:

<!-- 注入List類型屬性 -->
<bean id="boss" class="com.spring.model.Boss">  
    <property name="favorites">
        <list>
            <value>看報</value>
            <value>賽車</value>
            <value>高爾夫</value>
        </list>
    </property>
</bean>

List屬性既可以通過<value>注入字符串,也可以通過<ref>注入容器中的其他Bean。

2.Set:需要使用<set>標簽來配置注入,其配置參數及含義和<lsit>標簽完全一樣,具體配置例子如下:

<bean id=”……” class=”……”>
    <property name="……">
        <set>  
            <value>value1</value>  
            <value>value2</value>  
            ……  
        </set>
    </property>
</bean> 

3.Map:需要使用<map>標簽來配置注入,其屬性“key-type”和“value-type”分別指定“鍵”和“值”的數據類型。

在Boss類中添加一個Map類型的jobs屬性。

package com.spring.model;

import java.util.List;
import java.util.Map;

public class Boss {

    private Map jobs;
    
    public Map getJobs() {
        return jobs;
    }

    public void setJobs(Map jobs) {
        this.jobs = jobs;
    }

    public void print1(){
        System.out.println(jobs);
    }
}

在配置文件中可以通過以下方式為jobs屬性提供配置值。

<!-- 注入Map類型屬性 -->
<bean id="boss1" class="com.spring.model.Boss">  
    <property name="jobs">
        <map>
            <entry key="AM" value="會見客戶" />
            <entry key="PM" value="公司內部會議" />
        </map>
    </property>
</bean> 

其中<map>表示Map注入,<entry>表示鍵值對,<key>表示鍵數據,<value>表示鍵所對應的值數據。

4.Properties:需要使用<props>標簽來配置注入,鍵和值類型必須是String,不能變,子標簽<prop key=”鍵”>值</prop>來指定鍵值對。

Properties類型其實可以看成是Map類型的特例。Map元素的鍵和值可以是任何類型的對象,而Properties屬性的鍵和值都只能是字符串。為Boss添加一個Properties類型的mails屬性。

package com.spring.model;

import java.util.List;
import java.util.Map;
import java.util.Properties;

public class Boss {
    
    private Properties mails;
    
    public Properties getMails() {
        return mails;
    }

    public void setMails(Properties mails) {
        this.mails = mails;
    }
    
    public void print2(){
        System.out.println(mails);
    }
}

下面的配置片段為mails提供了配置。

<!-- 注入Properties類型屬性 -->
<bean id="boss2" class="com.spring.model.Boss">  
    <property name="mails">
        <props>
            <prop key="jobMail">john-office@163.com</prop>
            <prop key="lifeMail">john-life@163.com</prop>
        </props>
    </property>
</bean>

因為Properties鍵值對只能是字符串,因此其配置比Map的配置要簡單一些,注意值得配置沒有<value>子元素標簽。

·引用其他Bean

Spring IOC容器中定義的Bean可以相互引用,IOC容器則充當“紅娘”的角色。下面在Boss類中添加一個Car類型的屬性。

package com.spring.model;

import java.util.List;
import java.util.Map;
import java.util.Properties;

public class Boss {
    
    private Car car;
    //設置car屬性
    public void setCar(Car car) {
        this.car = car;
    }

    public void print3(){
        System.out.println(car.getBrand()+"----"+car.getPrice()+"----"+car.getMaxSpeed());
    }
}

boss的Bean通過<ref>元素引用car Bean,建立起boss對car的依賴。

<bean id="car" class="com.spring.model.Car">  
    <property name="maxSpeed" value="200"></property>
    <property name="brand" value="紅旗CA72"></property>  
    <property name="price" value="200000.00"></property>
</bean>
<!-- 通過ref元素引用bean -->
<bean id="boss3" class="com.spring.model.Boss">  
    <property name="car">
        <!--引用上面定義的car Bean-->
        <ref bean="car"></ref>
    </property>
</bean>

<ref>元素可以通過以下3個屬性引用容器中的其他Bean。
·  bean:通過該屬性可以引用同一容器或父容器的Bean,這是最常見的形式。

·  local:通過該屬性只能引用同一配置文件中定義的Bean,它可以利用XML解析器自動檢驗引用的合法性,以便在開發編寫配置時能夠及時發現並糾正配置的錯誤。

·  parent:引用父容器中的Bean,如<ref parent="car">的配置說明car的Bean是父容器中的Bean。

為了說明子容器對父容器中Bean的引用,來看一個具體的例子。假設有兩個配置文件beans1.xml和beans2.xml,其中beans1.xml被父容器加載,其配置內容如下。

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">
    
    <!--在父容器中定義的car -->
    <bean id="car" class="com.spring.model.Car">
        <property name="brand" value="紅旗CA72"></property> 
        <property name="maxSpeed" value="200"></property> 
        <property name="price" value="200000.00"></property>
    </bean>
    
</beans>

而beans2.xml被子容器加載,其配置內容如下。

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">
    
    <!--1.該Bean和父容器中的car Bean具有相同的id -->
    <bean id="car" class="com.spring.model.Car">  
        <property name="brand" value="吉利CT5"></property>  
        <property name="maxSpeed" value="100"></property>
        <property name="price" value="100000.00"></property>
    </bean>
    <bean id="boss" class="com.spring.model.Boss">  
        <property name="car">
            <!--引用父容器中的car,而非1處定義的Bean,如果采用<ref bean="car" />將引用本容器1處的car  -->
            <ref parent="car"></ref>
        </property>
    </bean>
</beans>

在beans1.xml中配置了一個car Bean,在beans2.xml中也配置了一個car Bean。分別通過父子容器加載beans1.xml和beans2.xml,beans2.xml中的boss通過<ref parent="car">將引用到父容器中的car。下面是分別加載beans1.xml和beans2.xml配置文件的代碼。

/**
 * 引用父容器中的bean
 */
@Test
public void test9(){
    //父容器
    ApplicationContext pFactory=new ClassPathXmlApplicationContext("beans1.xml");
    //指定pFactory為該容器的父容器
    ApplicationContext factory=new ClassPathXmlApplicationContext(new String[]{"beans2.xml"},pFactory);
    Boss boss=(Boss) factory.getBean("boss");
    System.out.println("引用父容器中的bean");
    System.out.println(boss.getCar().toString());
}

運行這段代碼,控制台中打印出以下的信息。

引用父容器中的bean
brand:紅旗CA72/maxSpeed:200/price:200000.0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM