Spring 學習筆記(五)—— Bean之間的關系、作用域、自動裝配
繼承
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之間的關系、作用域、自動裝配