1. 程式人生 > >Spring 學習筆記(五)—— Bean之間的關系、作用域、自動裝配

Spring 學習筆記(五)—— Bean之間的關系、作用域、自動裝配

mar byname pps etc 有時 sysman 對象實例 構造 encoding

繼承

  Spring提供了配置信息的繼承機制,可以通過為<bean>元素指定parent值重用已有的<bean>元素的配置信息。

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd"
> <bean id="baseuser" class="Demo05.BaseUser"> <property name="userid" value="1"/> <property name="username" value="rekent"/> <property name="password" value="123"/> </bean> <bean id="user1" parent
="baseuser"> <property name="userid" value="2"/> </bean> </beans>

  例如:上述我創建了一個BaseUser,其後的只要繼承了BaseUser的Bean都會有BaseUser的配置信息,此時只需要重寫不同的部分即可。

  註意:這裏的繼承是指配置信息的重用,與面向對象的繼承毫無關系。另外,Spring並沒有要求配置信息存在繼承關系的兩個Bean是統一類型的,只要具有相關屬性即可。


依賴

  Spring 通過Bean之間的引用ref建立了所有Bean之間的完整依賴關系,當實例化一個Bean時,IoC容器能保證該Bean所依賴的其他Bean已經初始化完畢。

  但是有時,可能要求Bean A的初始化必須在Bean B的初始化之後,而B不是A的屬性,因此無法通過向A註入B來保證首先完成B的創建。

  此時便提供了depends-on屬性來指定前置依賴的Bean。例如:

<bean id="father" class=""></bean>
<bean id="son" class="" depends-on="father"></bean>

作用域

  作用域通過<bean>元素的scope屬性指定,Spring支持5種作用域。

作用域 描述
singleton 一個Bean定義對應唯一一個對象實例,Bean以單實例的方式存在(默認)
prototype 一個Bean定義對應多個對象實例,每次調用getBean()時,就創建一個新實例(開銷大,不推薦)
request (僅在基於Web的SpringApplicationContext情形下有效)在一次Http請求中,一個Bean定義對應一個實例,即每個請求都會有各自的Bean。
session (僅在基於Web的SpringApplicationContext情形下有效)在一個HtppSession中,一個Bean定義對應一個實例。
global session (僅在基於Web的SpringApplicationContext情形下有效)在一個全局的Http Session中,一個Bean定義對應一個實例。

自動裝配(源於他人,原文鏈接:http://www.cnblogs.com/sysman/p/4485199.html)

可以使用bean元素的autowire屬性指定自動裝配的類型,spring支持如下類型:

自動裝配的類型 描述
no/default autowire="no"指定spring不使用自動裝配,需要手動裝配
byName 按照bean屬性的名字從spring容器中找同名的bean進行註入,適用於setter註入
byType 按照bean屬性的類型從spring容器中找相同類型的bean進行註入,適用於setter註入
constructor 按照類型裝配,跟byType類似.適用於構造器參數註入

下面我們將分別講解著四種裝配類型

不使用自動裝配-no

我們之前講解的所有的例子都屬於這種類型.在這種情況下所有bean的裝配都是手動進行的.我們再用一個例子復習下

1.新建包com.tutorialspoint.autowire,並在包中新建Cat.java、Dog.java、Duck.java.後面所有例子都會用到這三個類:

技術分享
//Cat.java
package com.tutorialspoint.autowire;

public class Cat {

    public void sayHi(){
        System.out.println("miao miao ... ");
    }
}

//Dog.java
package com.tutorialspoint.autowire;

public class Dog {

    public void sayHi(){
        System.out.println("wang wang ... ");
    }
}

//Duck.java
package com.tutorialspoint.autowire;

public class Duck {

    public void sayHi(){
        System.out.println("ga ga ... ");
    }
}
技術分享

2.新建包com.tutorialspoint.autowire.no,並在包中新建Zoo.java,內容如下:

技術分享
package com.tutorialspoint.autowire.no;

import com.tutorialspoint.autowire.*;

public class Zoo {

    private Cat cat;
    private Dog dog;
    private Duck duck;
    
    public void setCat(Cat cat) {
        this.cat = cat;
    }
    public void setDog(Dog dog) {
        this.dog = dog;
    }
    public void setDuck(Duck duck) {
        this.duck = duck;
    }
    
    public void print(){
        
        if(cat==null){
            System.out.println("cat is null");
        }else{
            cat.sayHi();
        }
        
        if(dog==null){
            System.out.println("dog is null");
        }else{
            dog.sayHi();
        }
        
        if(duck==null){
            System.out.println("duck is null");
        }else{
            duck.sayHi();
        }
    }
    
}
技術分享

3.在src目錄下新建autowire_no.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
   <bean id="cat" class="com.tutorialspoint.autowire.Cat"></bean>
   <bean id="dog" class="com.tutorialspoint.autowire.Dog"></bean>
   <bean id="duck" class="com.tutorialspoint.autowire.Duck"></bean>
  
   <bean id="zoo" class="com.tutorialspoint.autowire.no.Zoo">
       <property name="cat" ref="cat"></property>
       <property name="dog" ref="dog"></property>
   </bean>

</beans>
技術分享

4.在com.tutorialspoint.autowire.no包中新建MainApp.java.內容如下:

技術分享
package com.tutorialspoint.autowire.no;

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

public class MainApp {

    public static void main(String[] args) {
        
        ApplicationContext context = new ClassPathXmlApplicationContext("autowire_no.xml");
        
        Zoo zoo = (Zoo) context.getBean("zoo");
        
        zoo.print();
    }
}
技術分享

5.運行程序,檢查結果:

技術分享

通過上面的程序我們可以得出如下結論:

手動裝配bean,bean的所有依賴項都要在bean元素中明確指定.如果不進行指定spring容器就不會註入該屬性.

按照名字進行自動裝配-byName

在byName裝配方式下,spring首先會反射autowire="byName"的bean,得到bean中的所有屬性名(根據setter推算),然後從容

器中尋找同名的bean,最後把找到的bean註入到當前bean中.我們還是用代碼說話:

1.新建包com.tutorialspoint.autowire.byname,並在包中新建Zoo.java類.內容如下:

技術分享
package com.tutorialspoint.autowire.byname;

import com.tutorialspoint.autowire.Cat;
import com.tutorialspoint.autowire.Dog;
import com.tutorialspoint.autowire.Duck;

public class Zoo {

    private Cat cat;
    private Dog dog;
    private Duck duck;
    // 自動裝配並不適用於原始類型.這時候我們可以對該屬性進行手動裝配
    private String zooName;

    public void setZooName(String zooName) {
        this.zooName = zooName;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public void setDuck(Duck duck) {
        this.duck = duck;
    }

    public void print() {

        if (cat == null) {
            System.out.println("cat is null");
        } else {
            cat.sayHi();
        }

        if (dog == null) {
            System.out.println("dog is null");
        } else {
            dog.sayHi();
        }

        if (duck == null) {
            System.out.println("duck is null");
        } else {
            duck.sayHi();
        }
        
        System.out.println(zooName);
    }

}
技術分享

2.在src目錄下新建autowire_byName.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
   <!-- 名為zoo的bean在按照byName進行裝配的時候,可以適配名字為cat、dog
        的bean,不能適配名字為duck1的bean。所以最終zoo中會註入進cat和dog
        不會註入duck. -->
   <bean id="cat" class="com.tutorialspoint.autowire.Cat"></bean>
   <bean id="dog" class="com.tutorialspoint.autowire.Dog"></bean>
   <bean id="duck1" class="com.tutorialspoint.autowire.Duck"></bean>
   
   <bean id="zoo" class="com.tutorialspoint.autowire.byname.Zoo" autowire="byName">
       <!-- 由於自動裝配僅適用於引用類型,普通類型還需要手動進行註入 -->
       <property name="zooName" value="international_zoo"></property>
   </bean>

</beans>
技術分享

3.在包com.tutorialspoint.autowire.byname中新建MainApp.java.內容如下:

技術分享
package com.tutorialspoint.autowire.byname;

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

public class MainApp {

    public static void main(String[] args) {
        
        ApplicationContext context = new ClassPathXmlApplicationContext("autowire_byName.xml");
        
        Zoo zoo = (Zoo)context.getBean("zoo");
        
        zoo.print();
    }
}
技術分享

4.運行代碼,檢查結果:

技術分享

分析結果可以看到cat和dog已經按照屬性名字自動裝配到了zoo中.duck1由於沒有匹配的屬性名所以沒有進行裝配.zooName是

我們手動進行註入的。

按照類型進行自動裝配-byType

在byType裝配方式下,spring首先會反射autowire="byType"的bean,得到bean屬性的返回類型,然後去spring容器中按照類

型去匹配,最後把匹配到的bean註入到當前bean中.看個例子就明白了:

1.新建包com.tutorialspoint.autowire.bytype,並在包中新建Zoo.java類,內容如下:

技術分享
package com.tutorialspoint.autowire.bytype;

import com.tutorialspoint.autowire.Cat;
import com.tutorialspoint.autowire.Dog;
import com.tutorialspoint.autowire.Duck;

public class Zoo {

    private Cat cat;
    private Dog dog;
    private Duck duck;
    // 自動裝配並不適用於原始類型.這時候我們可以對該屬性進行手動裝配
    private String zooName;

    public void setZooName(String zooName) {
        this.zooName = zooName;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public void setDuck(Duck duck) {
        this.duck = duck;
    }

    public void print() {

        if (cat == null) {
            System.out.println("cat is null");
        } else {
            cat.sayHi();
        }

        if (dog == null) {
            System.out.println("dog is null");
        } else {
            dog.sayHi();
        }

        if (duck == null) {
            System.out.println("duck is null");
        } else {
            duck.sayHi();
        }

        System.out.println(zooName);
    }

}
技術分享

2.在src目錄下新建配置文件autowire_byType.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
   <!-- 名為zoo的bean在按照byType進行裝配的時候,可以適配名字為cat1、dog1、duck1
        的bean的類型。所以最終cat1、dog1、duck1會被分別註入進zoo的cat、dog、duck屬性。
        在按照類型進行裝配的時候,如過有兩個bean的類型符合的話,spring就不知道最終該使用哪個,這時候我們
        可以使用primary="true"告訴spring優先使用本bean
   -->
   <bean id="cat1" class="com.tutorialspoint.autowire.Cat" primary="true"></bean>
   <bean id="cat2" class="com.tutorialspoint.autowire.Cat"></bean>
   <bean id="dog1" class="com.tutorialspoint.autowire.Dog"></bean>
   <bean id="duck1" class="com.tutorialspoint.autowire.Duck"></bean>
   
   <bean id="zoo" class="com.tutorialspoint.autowire.bytype.Zoo" autowire="byType">
       <!-- 由於自動裝配僅適用於引用類型,普通類型還需要手動進行註入 -->
       <property name="zooName" value="international_zoo"></property>
   </bean>

</beans>
技術分享

3.在包com.tutorialspoint.autowire.bytype中新建MainApp.java。內容如下:

技術分享
package com.tutorialspoint.autowire.bytype;

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

public class MainApp {

    public static void main(String[] args) {
        
        ApplicationContext context = new ClassPathXmlApplicationContext("autowire_byType.xml");
        
        Zoo zoo = (Zoo)context.getBean("zoo");
        
        zoo.print();
    }
}
技術分享

4.運行程序,檢查結果:

技術分享

構造器參數類型自動裝配-constructor

在constructor自動裝配模式下,spring首先會反射bean的構造函數,得出構造函數的參數的類型,然後起spring容器中匹配合適的

類型的bean,最後使用構造器參數註入的方法把符合的bean註入到當前bean中。看代碼:

1.新建包com.tutorialspoint.autowire.constructor,並在包中新建Zoo.java。內容如下:

技術分享
package com.tutorialspoint.autowire.constructor;

import com.tutorialspoint.autowire.*;

public class Zoo {

    private Cat cat;
    private Dog dog;
    private Duck duck;
    private String zooName;
    
    public Zoo(Cat cat, Dog dog, Duck duck, String zooName) {
        this.cat = cat;
        this.dog = dog;
        this.duck = duck;
        this.zooName = zooName;
    }
    
    public void print() {

        if (cat == null) {
            System.out.println("cat is null");
        } else {
            cat.sayHi();
        }

        if (dog == null) {
            System.out.println("dog is null");
        } else {
            dog.sayHi();
        }

        if (duck == null) {
            System.out.println("duck is null");
        } else {
            duck.sayHi();
        }

        System.out.println(zooName);
    }

}
技術分享

2.在src目錄下新建autowire_constructor.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
   <!-- constructor跟byType十分相似.
        名為zoo的bean在按照constructor進行裝配的時候,可以適配名字為cat1、dog1、duck1
        的bean的類型。所以最終cat1、dog1、duck1會被分別註入進zoo的cat、dog、duck屬性(使用
        構造器參數進行註入)。
        在按照constructor進行裝配的時候,如過有兩個bean的類型符合的話,spring就不知道最終該使用哪個,這時候我們
        可以使用primary="true"告訴spring優先使用本bean
   -->
   <bean id="cat1" class="com.tutorialspoint.autowire.Cat" primary="true"></bean>
   <bean id="cat2" class="com.tutorialspoint.autowire.Cat"></bean>
   <bean id="dog" class="com.tutorialspoint.autowire.Dog"></bean>
   <bean id="duck1" class="com.tutorialspoint.autowire.Duck"></bean>
   
   <bean id="zoo" class="com.tutorialspoint.autowire.constructor.Zoo" autowire="constructor">
       <!-- 由於自動裝配僅適用於引用類型,普通類型還需要手動進行註入 -->
       <constructor-arg name="zooName" value="international_zoo"></constructor-arg>
   </bean>

</beans>
技術分享

3.在com.tutorialspoint.autowire.constructor包中新建MainApp.java。內容如下:

技術分享
package com.tutorialspoint.autowire.constructor;

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

public class MainApp {

    public static void main(String[] args) {
        
        ApplicationContext context = new ClassPathXmlApplicationContext("autowire_constructor.xml");
        
        Zoo zoo = (Zoo)context.getBean("zoo");
        
        zoo.print();
    }
}
技術分享

4.運行程序,檢查結果:

技術分享

如果使用sping的自動裝配,本人不推薦使用xml的配置方式.最好使用註解的配置方式。原因如下:

1.基於xml的自動裝配粒度態度。默認會裝配所有符合條件的bean.不能指定哪個屬性不進行自動裝配

2.不能指定哪些屬性必須進行裝配,否則拋出異常.

以上兩點使用spring的註解配置元數據都是可以做到的。我們下節就講解spring註解配置元數據。

Spring 學習筆記(五)—— Bean之間的關系、作用域、自動裝配