[TOC]
### 1.2. 容器概述
接口 *org.springframework.context.ApplicationContext* 代表Spring IoC容器,并負責實例化、配置和組裝上述beans。容器通過讀取配置元數據獲取需要實例化、配置和組裝的對象的指示信息。配置元數據用XML,Java注解或Java代碼表示。它允許你展示組成你的應用程序的對象以及這些對象之間豐富的相互依賴關系。
Spring提供了幾個 *ApplicationContext* 開箱即用的接口實現。在獨立應用程序中,通常會創建 *ClassPathXmlApplicationContext* 或 *FileSystemXmlApplicationContext* 的實例。雖然XML是用于定義配置元數據的傳統格式,但您可以通過提供少量的XML配置來指示容器使用Java注解或代碼作為元數據格式,以聲明方式支持這些其他元數據格式。
在大多數應用場景中,實例化Spring IoC容器的一個或多個實例不需要顯式的用戶代碼。例如,在Web應用程序場景中,應用程序的web.xml文件中簡單的8行(或多行)web樣板XML描述符就足夠了。如果您使用的是Spring工具套件Eclipse驅動的開發環境,則只需點擊幾下鼠標或按鍵即可輕松創建此樣板配置。
下圖是Spring如何工作的高級視圖。您的應用程序類與配置元數據相結合,則在創建并初始化 *ApplicationContext* 之后,您擁有完全配置且可執行的系統或應用程序。
:-: 
#### 1.2.1. 配置元數據
如上圖所示,Spring IoC容器使用一種配置元數據的形式;此配置元數據表示作為應用程序開發人員如何告訴Spring容器在您的應用程序中實例化、配置和組裝對象。
傳統上,配置元數據是以簡單直觀的XML格式提供的,這是本章大部分內容用來傳達Spring IoC容器的關鍵概念和功能的格式。
>[info] 基于XML的元數據不是唯一允許的配置元數據形式。Spring IoC容器本身與配置元數據實際使用格式完全分離。現在很多開發人員在他們的Spring應用程序中選擇基于Java的配置。
有關在Spring容器中使用其他形式的元數據的信息,請參閱:
- 基于注解的配置:Spring 2.5引入了對基于注解的配置元數據的支持。
- 基于Java的配置:從Spring 3.0開始,Spring JavaConfig項目提供的許多功能成為核心Spring框架的一部分。因此,您可以使用Java而不是XML文件來定義應用程序類外部的Beans。要使用這些新功能,請參閱@Configuration,@Bean,@Import和@DependsOn注解。
Spring配置由的至少一個,通常是多個bean定義組成,這些bean容器必須管理。基于XML的配置元數據用\ <bean
/> 元素作為beans的配置,并放置在頂級\<beans />元素內。Java配置通常使用由@Bean注解的方法,該方法位于@Configuration 注解的類中。
這些bean定義對應于組成應用程序的實際對象。通常,您可以定義服務層對象,數據訪問對象(DAOs),Struts Action實例等表示層對象,Hibernate SessionFactories等基礎結構對象,JMS隊列等。通常,不會在容器中配置細粒度的域對象,因為創建和加載域對象通常是DAO和業務邏輯的責任。但是,您可以使用Spring與AspectJ的集成來配置在IoC容器控制之外創建的對象。請參閱 **使用AspectJ依賴注入Spring使用的域對象**。
以下示例顯示了基于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;有關更多信息,請參閱**依賴關系**。
#### 1.2.2. 實例化容器
實例化Spring IoC容器很簡單。提供給 *ApplicationContext* 構造函數的位置路徑實際上是資源字符串,它允許容器從各種外部資源(例如本地文件系統,Java CLASSPATH等等)加載配置元數據。
~~~
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
~~~
>[info] 在了解了Spring的IoC容器之后,您可能想了解更多關于Spring的資源抽象的知識,如參考資料中所述,它提供了一種從URI語法中定義的位置讀取InputStream的方便機制。特別是,資源路徑用于構建應用程序上下文,如 **應用程序上下文和資源路徑中** 所述。
以下示例顯示服務層對象(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的配置元數據
讓bean定義跨越多個XML文件可能很有用。通常,每個單獨的XML配置文件都代表了架構中的邏輯層或模塊。
您可以使用應用程序上下文構造函數從所有這些XML片段中加載bean定義。這個構造函數有多個資源位置,如前一節所示。或者,使用一個或多個\<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>
~~~
在前面的示例中,從三個文件加載外部bean定義:services.xml,messageSource.xml和themeSource.xml。所有位置路徑都與導入的定義文件相關,因此services.xml必須位于與導入文件相同的目錄或類路徑位置,而messageSource.xml和themeSource.xml必須位于導入文件位置下下層的位置。正如你所看到的,一個前導斜線被忽略,但是鑒于這些路徑是相對的,最好不要使用斜線。根據Spring Schema,導入的文件的內容(包括頂級\<beans />元素)必須是有效的XML bean定義。
>[info] 可以但不推薦使用“../”這樣的相對路徑引用父目錄中的文件。這樣做會創建對當前應用程序外部的文件的依賴關系。特別是,不建議將此方法用于“classpath:”URLs(例如“classpath:../ services.xml”),來在運行時解析過程中選擇“最近”的classpath根,然后查看其父目錄。Classpath 配置更改可能會導致選擇不同的,不正確的目錄。
>
> 您始終可以使用完全限定的資源位置而不是相對路徑:例如,“file:C:/config/services.xml”或“classpath:/config/services.xml”。但是,請注意,您將應用程序的配置與特定絕對位置相關聯。通常最好保持這種絕對位置的間接性,例如通過在運行時根據JVM系統屬性解析的“$ {...}”占位符。
import指令是由beans名稱空間本身提供的一項功能。除了普通bean定義以外的其他配置特性在由Spring提供的XML名稱空間的selection是可用的,例如,“context”和“util”命名空間。
##### Groovy Bean Definition DSL
作為外部化配置元數據的另一個例子,bean的定義也可以在Spring的Groovy Bean Definition DSL中表示,如Grails框架中所知。通常,這樣的配置將存在于“.groovy”文件中,結構如下:
~~~
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
~~~
這種配置風格很大程度上等同于XML bean定義,甚至支持Spring的XML配置名稱空間。它還允許通過“importBeans”指令導入XML bean定義文件。
#### 1.2.3. 使用容器
*ApplicationContext* 是高級工廠的接口,能夠維護不同Beans及其依賴項的注冊表。使用方法 *T getBean (String name, Class \<T> requiredType)* 方法,可以檢索beans的實例。
*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配置,引導看起來非常相似,只是一個不同的上下文實現類,它可以感知Groovy(但也理解XML bean定義):
~~~
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
~~~
最靈活的變體是GenericApplicationContext與 reader 委派組合,例如,使用讀取XML文件的 *XmlBeanDefinitionReader*:
~~~
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
~~~
或者使用Groovy文件的 *GroovyBeanDefinitionReader*:
~~~
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
~~~
如果需要,這樣的reader委派可以在同一個 *ApplicationContext* 上混合和匹配,從不同的配置源讀取bean定義。
然后可以使用 *getBean* 來檢索beans的實例。*ApplicationContext* 接口還有其他一些檢索beans的方法,但理想情況下,應用程序代碼不應該使用它們。事實上,你的應用程序代碼根本不應該調用 *getBean()* 方法,因此完全不依賴于Spring API。例如,Spring與Web框架的集成為各種Web框架組件(如控制器和JSF托管的Beans)提供了依賴注入,允許您通過元數據(例如自動裝配注解)聲明對特定Bean的依賴關系。