一、概述
容器是Spring框架的核心,Spring容器使用IOC管理所有組成應用系統的組件。Spring有兩種不同的容器:BeanFactory提供最簡單的容器,提供了最基礎的依賴注入支持,ApplicationContext建立在BeanFactory的基礎之上,提供了系統構架服務如從屬性文件中讀取文本信息,事件傳遞等。
在Spring容器中拼湊Bean叫做裝配,裝配Bean的時候,你是在告訴容器需要哪些Bean以及容器如何使用依賴注入將它們配合在一起。
二、裝配Bean
2.1 使用XML裝配
BeanFactory采用工廠設計模式,它的實現類負責創建和分發各種類型的Bean。
Spring中有幾種BeanFactory的實現,例如org.springframework.beans.factory.xml.XmlBeanFactory根據XML文件中的定義裝載Bean。(現在已經不建議使用)
ClassPathXmlApplicationContext:一種上下文,它從類路徑中載入上下文定義文件
FileSystemXmlApplicationContext:一種應用上下文,它從文件系統中載入上下文文件
XmlWebApplicationContext:一種基於Spring的web應用系統上下文,從web應用上下文中載入上下文定義文件
public class TestMain { public static void main(String[] args) { //ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); ClassPathResource res = new ClassPathResource("applicationContext.xml"); BeanFactory factory=new XmlBeanFactory(res);//XmlBeanFactory現在已經不建議使用 Demo2 t=(Demo2) factory.getBean("demo2"); System.out.println(t.getPrice()); } }
2.2 添加一個bean
Bean工廠從XML文件中讀取Bean的定義信息,但是此時還沒有實例化Bean,Bean是被延遲載入到Bean工廠中的。然后調用getBean方法,工廠就會實例化Bean並且使用依賴注入開始設置Bean的屬性。
一個最基本的BeanFactory配置由一個或多個它所管理的Bean定義組成,在一個XmlBeanFactory中,根節點beans中包含一個或多個元素
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="..." class="..."> ... </bean> <bean id="..." class="..."> ... </bean> ... </beans>
一個XmlBeanFactory中的Bean定義包括:
- classname:通常是bean的真正的實現類,但是如果一個bean使用一個靜態工廠方法所創建而不是被普通的構造函數創建,那么這就是工廠類的classname
- bean行為配置元素:它聲明這個bean在容器中的行為方式,比如自動裝配模式、依賴檢查模式、初始化和析構方法
- 構造函數的參數和新創建bean所需要的屬性:比如池的大小限制
- 和這個bean工作相關的其他bean:比如它的合作者
方向控制/依賴注入存在兩種主要的形式:
1、基於setter的依賴注入:是在調用無參構造函數或無參的靜態方法工廠方法實例化你的bean之后,通過調用你的bean上的setter方法實現的。Spring一般提倡使用基於setter方法的依賴注入。下面就這種方法距離:
構建Bean的實現類為Demo1.java:
public class Demo1 { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Demo1() { System.out.println("調用無參構造函數"); } }
applicationContext.xml中的配置為:
<bean id="demo1" class="com.Demo1"> <property name="name"> <value>xujian</value> </property> <property name="age"> <value>23</value> </property> </bean>
編寫測試類:
public class TestMain { public static void main(String[] args) { ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml"); Demo1 t=(Demo1) factory.getBean("demo1"); System.out.println(t.getName()); } }
運行結果為:
可見,通過setter方法,先是執行了該類的無參構造函數,然后調用setXXX方法來設置屬性。
2、基於構造函數的依賴注入:它是通過調用帶有許多參數的構造方法來實現的,每個參數表示一個合作者或者屬性,下面就這種方法舉例
使用這種方法,需要在bean的實現類中添加有參構造函數
public class Demo2 { private String bookName; private int price; public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public Demo2(String bookName, int price) { System.out.println("執行有參構造函數!"); this.bookName = bookName; this.price = price; } }
對應applicationContext.xml的配置為:
<bean id="demo2" class="com.Demo2" > <constructor-arg> <value>Java</value> </constructor-arg> <constructor-arg> <value>50</value> </constructor-arg> </bean>
編寫測試類:
public class TestMain { public static void main(String[] args) { ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml"); Demo2 t=(Demo2) factory.getBean("demo2"); System.out.println(t.getBookName()); } }
執行結果為:
2.3 原型與單實例
Spring在缺省情況下是單實例模式,在容器分配Bean的時候總是返回同一個實例。
測試如下:
public class TestMain { public static void main(String[] args) { ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml"); Demo2 t1=(Demo2) factory.getBean("demo2"); Demo2 t2=(Demo2) factory.getBean("demo2"); System.out.println(t1==t2); } }
執行結果為:
如果我們想每次向上下文請求一個Bean的時候總是得到一個不同的實例,則需要配置scope屬性,在原配置文件中scope的默認值是singleton,現在將其設置為prototype
<bean id="demo2" class="com.Demo2" scope="prototype"> <constructor-arg> <value>Java</value> </constructor-arg> <constructor-arg> <value>50</value> </constructor-arg> </bean>
再次執行上面的測試程序,結果如下:
2.4 實例化與銷毀
當一個Bean實例化的時候,可能需要做一些初始化的工作,刪除的時候需要做一些清理工作,在Bean的定義中設置自己的init-method和destroy-method並在xml文件中進行配置,這些方法就會在實例化創建或者銷毀的時候被調用。示例如下:
在Demo2類的定義中添加兩個函數
public void initialize() { System.out.println("執行了初始化函數!"); } public void close() { System.out.println("執行了銷毀函數!"); }
然后配置XMl文件
<bean id="demo2" class="com.Demo2" init-method="initialize" destroy-method="close"> <constructor-arg> <value>Java</value> </constructor-arg> <constructor-arg> <value>50</value> </constructor-arg> </bean>
運行測試程序
public class TestMain { public static void main(String[] args) { ApplicationContext factory=new ClassPathXmlApplicationContext("applicationContext.xml"); Demo2 t1=(Demo2) factory.getBean("demo2"); System.out.println(t1.getBookName()); t1.close(); } }
結果如下:
2.5 自動裝配
我們可以通過設置bean中的autowire屬性來實現自動裝配。有四種自動裝配的類型:
- byName:試圖在容器中尋找和需要自動裝配的屬性名相同的Bean
- byType:在容器中尋找與需要自動裝配的屬性類型相同的Bean
- constructor:在容器中尋找與需要自動裝配的Bean的構造函數參數一致的一個或多個Bean
- null:無自動裝配模式,Bean的引用必須要通過ref元素定義