Spring的核心技術(二)---容器簡介
org.springframework.context.ApplicationContext介面代表了Spring的IoC容器,並且它負責例項化、配置和組裝前面提到的Bean物件。這個容器通過 讀取配置元資料來獲得要例項化、配置和組裝的物件的指令。配置元資料被放在XML檔案、Java註解或Java程式碼中,你可以用這些元資料來描述構成應用程式的物件以及這些物件之間的豐富的內部依賴關係。
Spring提供了幾個即裝即用的ApplicationContext介面的實現。在獨立的應用程式中,通常要建立一個ClassPathXmlApplicationContext類或FileSystemXmlApplicationContext類的例項。雖然可以使用傳統的XML格式來定義配置元資料,但是也通過提供一個宣告啟用其他元資料格式的小的XML配置來指示容器 使用Java註解或程式碼作為配置元資料。
在大多數應用場景中,使用者無需明確的例項化Spring的IoC容器。例如,在一個Web應用場景中,在應用的web.xml檔案中通常只需要簡單的8行樣板化的Web描述符就足夠了(詳細請看“方便的Web應用程式的ApplicationContext例項化”)。如果使用基於Eclipse的Spring開發套件,只需點幾下滑鼠或鍵盤就可以很容易的建立樣板配置。
下圖是一個Spring如何工作的高階檢視。應用程式的類有配置元資料來組合,以便由後續的ApplicationContext介面來建立和初始化,這樣就有了一個完全可配置和執行的系統或應用程式。
Spring的IoC容器 |
1. 配置元資料
如上圖所示,Spring的IoC容器要使用一種格式的配置元資料,這個配置元資料代表了應用程式的開發者告訴Spring的容器如何例項化、配置和組裝應用程式中的物件。
傳統的配置元資料是以簡單直觀的XML格式來提供的,所以本章大都使用這種格式來傳達Spring IoC容器的關鍵概念和功能。
提示:基於XML的元資料不是配置元資料僅有的格式。Spring的IoC容器本身是完全與實際編寫的配置元資料的格式解耦的。現在很多開發者都為他們的應用程式選擇了基於Java的配置。
關於Spring容器所使用的其他格式的元資料,請看以下內容:
l 基於註解的配置:從Spring2.5開始引入了對基於註解的配置元資料的支援;
l 基於Java的配置:從Spring3.0開始,由Spring的JavaConfig專案所提供的很多功能成為核心Spring框架的一部分。因此通過使用Java而不是XML檔案就可以給應用程式的類定義外部的Bean。要使用這些新功能,請看@Configuration、@Bean、@Import、和@DependsOn註解。
Spring的配置包含了至少一個必須由容器來管理的Bean定義。基於XML的配置元資料會把這些Bean的配置作為<bean/>元素放到頂層的<beans/>元素內部。Java配置通常使用@Configuration類中的@Bean註解方法。
這些Bean定義相當於構成應用程式的實際的物件。通常要定義服務層物件、資料訪問物件(DAO)、展現層物件(如Struts的Action例項)、基礎物件(如Hibernate的SessionFactories)、JMS的Queues等等。通常不會在容器內配置細粒度的域物件,因為這通常是由建立和載入域物件的DAO和業務邏輯來負責的。但是,可以使用Spring跟AspectJ的整合來配置在IoC容器控制之外所建立的配置物件,詳細請看“跟Spring一起使用AspectJ來注入依賴域物件”。
下面的示例展示了基於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.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
id屬性是一個字串,它用於標識獨立的Bean定義。Class屬性使用完整的合規的類名定義了Bean的型別,id屬性的值指向要合作的對像,這個XML示例沒有展示要合作的物件,詳細資訊請看“依賴”。
2. 例項化一個容器
可以很簡單的例項化一個Spring的IoC容器。提供給ApplicationContext構造器的位置路徑是實際的資源字串,它們指向了容器要載入的配置元資料所在的外部資源的位置,如本地檔案系統、Java的CLASSPATH等等。
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
提示:學習了有關Spring的IoC容器之後,就可能想要了解更多有關Spring的Resource的抽象,第7章介紹的“Resources”提供了一種方便的從URI格式的位置定義中讀取輸入流的機制。實際上,Resource路徑被用於構建應用的上下文環境,詳細請看“應用程式的上下文環境和資源路徑”。
以下是一個展示服務層物件(services.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.xsd">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
以下是一個展示資料訪問物件daos.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.xsd">
<bean id="accountDao"
class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for data access objects go here -->
</beans>
在前面的示例中,服務層由類PetStoreServiceImpl和兩個資料訪問物件JpaAccountDao和JpaItemDao構成(這兩個資料訪問物件是基於JPA的物件/關係對映標準)。property的name屬性指向了JavaBean屬性的名字,ref屬性指向了另外的Bean定義的名稱。id和ref屬性之間的關係傳遞了合作物件之間的依賴。配置物件間依賴的詳細資訊請看“依賴”。
基於XML的配置元資料的組成
把配置元資料定義到多個XML檔案中是有好處的,通常每個獨立的XML配置檔案代表了架構中的一個邏輯層或模組。
使用應用程式的上下文構造器從這些XML片段中載入Bean的定義。這個構造器需要如前所示多個Resource的位置。一種可選的方法是使用一個或多個<import/>元素從不同的檔案中載入Bean的定義,例如:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
在前面的示例中,從services.xml、messageSource.xml和themeSource.xml三個檔案中載入外部的Bean定義。所有的位置路徑都是相對於入口的定義檔案,因此services.xml必須在入口檔案相同的目錄或類路徑中,而messageSource.xml和themeSource.xml必須在入口檔案路徑下的resources路徑中,如上所示,可以忽略前面的斜槓,由於這些路徑是相對的,所以比較好的格式是不使用斜槓。被匯入的檔案的內容,包括頂層的<beans/>元素,必須根據Spring的方案定義的有效的XML的Bean定義。
提示:儘管可以,但是不推薦使用相對的“../”路徑來引用父目錄中的檔案。這樣做會要求建立一個依賴當前應用程式之外的檔案。實際上,這個引用不推薦使用“classpath:”樣式的URL(例如,“classpath:../services.xml”),通常執行時會先選擇檢視類路徑,然後才會檢視應用的父目錄,因此類路徑配置的改變會導致不同的選擇,從而選擇錯誤大的目錄。
可以始終使用絕對資源路徑來代替相對路徑,例如“file:C/config/services.xml”或“classpath:/config/services.xml”。但是,要知道把應用程式的配置指定到絕對路徑,通常會優先給這些絕對路徑保留一個間接的引用,例如通過“${…}”佔位符來解決與JVM系統執行時屬性的衝突。
3. 使用容器
ApplicationContext是能夠保持不同的Bean以及它們的依賴的高階工廠介面。使用T getBean(String name,Class<T> requiredType)方法能夠獲取相應的Bean的型別。
ApplicationContext能夠像下面這樣讀取和訪問Bean定義:
// create and configure beans
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
使用getBean()方法來獲取Bean的例項。ApplicationContext介面還有幾個其他的獲取Bean的方法,但是理想情況下,應用程式程式碼不應該使用它們。事實上應用程式不應該呼叫getBean()方法,因此不會依賴Spring的API。例如,Spring的整合Web框架為依賴注入提供了諸如控制器和管理JSF Bean的各種Web框架 。