1.2. 容器概述
org.springframework.context.ApplicationContext接口代表 Spring IoC 容器,并負責(zé)實例化,配置和組裝 Bean。容器通過讀取配置元數(shù)據(jù)來獲取有關(guān)要實例化,配置和組裝哪些對象的指令。配置元數(shù)據(jù)以 XML,Java 注解或 Java 代碼表示。它使您能夠表達組成應(yīng)用程序的對象以及這些對象之間豐富的相互依賴關(guān)系。
Spring 提供了ApplicationContext接口的幾種實現(xiàn)。在獨立應(yīng)用程序中,通常創(chuàng)建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext的實例。雖然XML一直是定義配置元數(shù)據(jù)的傳統(tǒng)格式,但您可以通過提供少量XML配置來指示容器使用Java注釋或代碼作為元數(shù)據(jù)格式,以聲明方式支持這些額外的元數(shù)據(jù)格式。
在大多數(shù)應(yīng)用場景中,實例化 Spring IoC 容器的一個或多個實例不需要顯式的用戶代碼。例如,在 Web 應(yīng)用程序場景中,web.xml文件中簡單的8行左右的關(guān)于描述 web 的樣板通常就足夠了(請參閱Convenient ApplicationContext Instantiation for Web Applications。如果使用Spring Tools for Eclipse(基于 Eclipse 的開發(fā)環(huán)境),那么僅需單擊幾次鼠標(biāo)或擊鍵即可輕松創(chuàng)建此樣板配置。
下圖顯示了 Spring 的如何工作的高級視圖。您的應(yīng)用程序類與配置元數(shù)據(jù)結(jié)合在一起,這樣,在創(chuàng)建和初始化ApplicationContext之后,您將具有完全配置和可執(zhí)行的系統(tǒng)或應(yīng)用程序。

Figure 1. The Spring IoC container
1.2.1 配置元數(shù)據(jù)
如上圖所示,Spring IoC 容器使用一種配置元數(shù)據(jù)的格式。此配置元數(shù)據(jù)表示您作為應(yīng)用程序開發(fā)人員如何告訴 Spring 容器實例化,配置和組裝應(yīng)用程序中的對象。
傳統(tǒng)方法是使用簡單直觀的 XML 格式配置元數(shù)據(jù),這是本章大部分內(nèi)容以此方法傳達 Spring IoC 容器的關(guān)鍵概念和功能。
Note
基于 XML 的元數(shù)據(jù)不是配置元數(shù)據(jù)的唯一允許格式。 Spring IoC 容器本身與實際寫入此配置元數(shù)據(jù)的格式是完全脫鉤的。如今,許多開發(fā)人員為自己的 Spring 應(yīng)用程序選擇Java-based configuration。
有關(guān)在 Spring 容器中使用其他形式的元數(shù)據(jù)的信息,請參見:
Annotation-based configuration:Spring 2.5 引入了對基于注解的配置元數(shù)據(jù)的支持。
Java-based configuration:從 Spring 3.0 開始,Spring JavaConfig 項目提供的許多功能成為了core Spring Framework 的一部分。因此,您可以使用 Java 而不是 XML 文件來定義應(yīng)用程序類外部的 bean。要使用這些新功能,請參見@Configuration,@Bean,@Import和@DependsOn注解。
Spring 配置包含容器管理的至少一個bean定義,通常是多個bean定義?;?XML 的配置元數(shù)據(jù)將這些 bean 配置為<beans/>元素內(nèi)的<bean/>元素。 Java 配置通常在@Configuration類中使用@Bean
注解的方法。
這些 bean 定義對應(yīng)于組成應(yīng)用程序的實際對象。通常,您定義服務(wù)層對象,數(shù)據(jù)訪問對象(DAO),展示對象(例如 控制層實例),基礎(chǔ)設(shè)施對象(例如 Hibernate SessionFactories,JMS Queues等)。通常,不會在容器中配置細粒度的域?qū)ο螅驗?DAO 和業(yè)務(wù)邏輯通常負責(zé)創(chuàng)建和加載域?qū)ο?。但是,您可以使?Spring 與 AspectJ 的集成來配置在 IoC 容器的控制范圍之外創(chuàng)建的對象。參見使用 Spring 與 AspectJ 來依賴注入對象。
以下示例顯示了基于 XML 的配置元數(shù)據(jù)的基本結(jié)構(gòu):
<?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
https://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 屬性是標(biāo)識單個 bean 定義的字符串。
- class 屬性使用完整的類名并定義 bean 的類型。
id 屬性的值涉及到有協(xié)作關(guān)系的其他對象。在此XML示例中未顯示有協(xié)作關(guān)系的其他對象 。有關(guān)更多信息,請參見Dependencies。
1.2.2. 實例化容器
提供給ApplicationContext構(gòu)造函數(shù)的 location path 或路徑是resource strings,使容器從自各種外部資源加載配置元數(shù)據(jù),例如本地文件系統(tǒng),CLASSPATH等。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
Note
了解了 Spring 的 IoC 容器之后,您可能想了解更多有關(guān) Spring 的Resource抽象(如Resources中所述),該抽象為從 URI 語法中定義的 locations 讀取 InputStream 提供了一種方便的機制。特別是,Resource路徑用于構(gòu)建應(yīng)用程序上下文,如Application Contexts and Resource Paths中所述。
以下示例顯示了服務(wù)層對象(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
https://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>
以下示例顯示了數(shù)據(jù)訪問對象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
https://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>
在前面的示例中,服務(wù)層由PetStoreServiceImpl類和兩個類型為JpaAccountDao和JpaItemDao的數(shù)據(jù)訪問對象組成(基于 JPA 對象關(guān)系映射標(biāo)準(zhǔn))。 property name元素表示 JavaBean 屬性 的名稱,而ref元素表示另一個 bean definition 的名稱。 id和ref元素之間的這種聯(lián)系表達了協(xié)作對象之間的依賴性關(guān)系。有關(guān)配置對象的依賴項的詳細信息,請參見Dependencies。
構(gòu)成基于 XML 的配置元數(shù)據(jù)
使 bean 定義跨越多個 XML 文件是很有用的。通常,每個單獨的 XML 配置文件都代表架構(gòu)中的邏輯層或模塊。
您可以使用 application context 的構(gòu)造函數(shù)從所有這些 XML 片段中加載 bean definition。該構(gòu)造函數(shù)具有多個Resource位置,如previous section所示。或者,使用一個或多個<import/>元素從另一個文件中加載 bean 定義。以下示例顯示了如何執(zhí)行此操作:
<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 定義。所有位置路徑都相對于進行導(dǎo)入的定義文件,因此services.xml必須與進行導(dǎo)入的文件位于同一目錄或 Classpath 位置,而messageSource.xml和themeSource.xml必須位于導(dǎo)入文件位置下方的resources位置。如您所見,斜杠被忽略。但是,鑒于這些路徑是相對的,最好不要使用任何斜線。根據(jù) Spring Schema,導(dǎo)入的文件的內(nèi)容(包括頂級<beans/>元素)必須是有效的 XML bean 定義。
Note
可以但不建議使用相對的“ ../”路徑引用父目錄中的文件。這樣做會創(chuàng)建對當(dāng)前應(yīng)用程序外部文件的依賴關(guān)系。特別是,不建議對classpath: URL(例如classpath:../services.xml)使用此引用,在 URL 中,運行時解析過程選擇“最近”Classpath 根,然后查看其父目錄。Classpath 配置的更改可能導(dǎo)致選擇其他錯誤的目錄。
您始終可以使用標(biāo)準(zhǔn)資源位置而不是相對路徑:例如file:C:/config/services.xml或classpath:/config/services.xml。但是,請注意,您正在將應(yīng)用程序的配置耦合到特定的絕對位置。通常,最好為這樣的絕對位置保留一個間接尋址,例如通過在運行時針對 JVM 系統(tǒng)屬性解析的“ ${…}”占位符。
名稱空間本身提供了導(dǎo)入指令功能。 Spring 提供的一系列 XML 名稱空間(例如context和util名稱空間)中提供了超出普通 bean 定義的其他配置功能。
The Groovy Bean Definition DSL
略
1.2.3. 使用容器
ApplicationContext是高級工廠的接口,能夠維護不同bean及其依賴項的注冊表。通過使用方法 T getBean(String name, Class<T> requiredType),您可以檢索 bean 的實例。
ApplicationContext允許您讀取 bean 定義并訪問它們,如以下示例所示:
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
對于Groovy配置,引導(dǎo)看起來非常相似。它有一個不同的上下文實現(xiàn)類,它可以感知Groovy(同時也理解XML Bean定義)。下面的示例顯示Groovy配置:
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
最靈活的變體是GenericApplicationContext與 讀取器 結(jié)合使用,例如,對于 XML 文件,是XmlBeanDefinitionReader,如以下示例所示:
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
您還可以將GroovyBeanDefinitionReader用于 Groovy 文件,如以下示例所示:
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
您可以在相同的ApplicationContext上混合并匹配此類閱讀器委托,從不同的配置源讀取 Bean 定義。
然后,您可以使用getBean來檢索 bean 的實例。 ApplicationContext接口還有其他幾種檢索 bean 的方法,但是理想情況下,您的應(yīng)用程序代碼永遠不要使用它們。實際上,您的應(yīng)用程序代碼應(yīng)該根本不調(diào)用getBean()方法,因此完全不依賴于 Spring API。例如,Spring 與 Web 框架的集成為各種 Web 框架組件(例如controllers 和 JSF-managed beans)提供了依賴注入,使您可以通過元數(shù)據(jù)(例如自動裝配)聲明對特定 Bean 的依賴。