本章介紹Spring Framework實現控制反轉(IoC)[1]原理。IoC也被稱爲依賴注入(DI)。它是一個過程,對象經過構造函數參數,工廠方法的參數或在工廠方法構造或返回後在對象實例上設置的屬性來定義它們的依賴關係,即它們使用的其餘對象。容器在建立bean時會注入這些依賴關係。這個過程從根本上來講是相反的,所以名爲控制反轉(IoC),bean自己經過使用類的直接構造來控制其依賴關係的實例化或位置,或者諸如服務定位器模式。html
在org.springframework.beans
和 org.springframework.context
包是Spring框架的IoC容器的基礎。該BeanFactory
接口提供了一種可以管理任何類型對象的高級配置機制。 ApplicationContext
是一個子接口 BeanFactory.
它增長了與Spring的AOP特性的更容易的集成; 消息資源處理(用於國際化),事件發佈; 和特定於應用層的上下文(例如,WebApplicationContext
用於Web應用程序中)。java
簡而言之,它BeanFactory
提供了配置框架和基本功能,並 ApplicationContext
增長了更多的企業特定功能。這 ApplicationContext
是一個完整的超集BeanFactory
,並在本章中專門用於描述Spring的IoC容器。有關使用BeanFactory
而不是ApplicationContext,
參考第5.15節「The BeanFactory」的更多信息。web
在Spring中,構成應用程序主幹和由Spring IoC 容器管理的對象稱爲bean。bean是一個實例化,組裝並由Spring IoC容器管理的對象。不然,bean只是應用程序中衆多對象中的一個。Bean和它們之間的依賴關係反映在容器使用的配置元數據中。spring
該接口 org.springframework.context.ApplicationContext
表示Spring IoC容器,並負責實例化,配置和組裝上述bean。容器經過讀取配置元數據獲取有關要實例化,配置和組裝的對象的指示信息。配置元數據用XML,Java註釋或Java代碼表示。它容許您表示組成應用程序的對象以及這些對象之間豐富的相互依賴關係。apache
ApplicationContext
Spring提供了幾個接口的實現 。在獨立應用程序中,一般會建立一個ClassPathXmlApplicationContext
or 的實例FileSystemXmlApplicationContext
。雖然XML是用於定義配置元數據的傳統格式,但您能夠經過提供少許的XML配置來指示容器使用Java註釋或代碼做爲元數據格式,以聲明方式支持這些其餘元數據格式。api
在大多數應用場景中,顯式用戶代碼不須要實例化Spring IoC容器的一個或多個實例。例如,在Web應用程序場景中,應用程序文件中簡單的八行(或多行)樣板J2EE Web描述符XML web.xml
一般就足夠了(請參見第5.14.4節「 ApplicationContext
Web應用程序的便捷實例」)。若是您使用的是SpringSource Tool Suite Eclipse驅動的開發環境或Spring Roo,則只需點擊幾下鼠標或擊鍵便可輕鬆建立此樣板配置。架構
下圖是Spring如何工做的高級視圖。您的應用程序類與配置元數據相結合,以便在ApplicationContext
建立並初始化以後,您擁有徹底配置且可執行的系統或應用程序。app
Spring IoC容器框架
如上圖所示,Spring IoC容器使用一種形式的配置元數據 ; 此配置元數據表示做爲應用程序開發人員如何告訴Spring容器在您的應用程序中實例化,配置和組裝對象。函數
配置元數據傳統上以簡單直觀的XML格式提供,這是本章的大部份內容用來傳達Spring IoC容器的關鍵概念和功能。
![]() |
基於XML的元數據不是惟一容許的配置元數據形式。Spring IoC容器自己 徹底與此配置元數據實際寫入的格式分離。 |
有關在Spring容器中使用其餘形式的元數據的信息,請參閱:
基於註釋的配置:Spring 2.5引入了對基於註釋的配置元數據的支持。
基於Java的配置:從Spring 3.0開始,Spring JavaConfig項目提供的許多功能成爲核心Spring框架的一部分。所以,您可使用Java而不是XML文件來定義應用程序類外部的Bean。要使用這些新功能,請參閱 @Configuration
,@Bean, @Import
和 @DependsOn
註釋。
Spring配置由容器必須管理的至少一個,一般是多個bean定義組成。基於XML的配置元數據將這些bean配置爲 <bean/>
頂層元素內的 <beans/>
元素。
這些bean定義對應於組成應用程序的實際對象。一般,您能夠定義服務層對象,數據訪問對象(DAO),Struts Action
實例等表示對象 ,Hibernate SessionFactories
,JMS 等基礎結構對象Queues
。一般,不會在容器中配置細粒度的域對象,由於建立和加載域對象一般是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 = 「...」 > <! - 此bean的協做者和配置轉到此處 - > </ bean> <bean id = 「...」 class = 「...」 > <! - 此bean的協做者和配置轉到此處 - > </ bean> <! - 更多的bean定義在這裏 - > </bean>
該id
屬性是一個用來標識單個bean定義的字符串。該class
屬性定義了bean的類型並使用徹底限定的類名。id屬性的值是指協做對象。本示例中未顯示用於引用協做對象的XML; 有關更多信息,請參閱依賴關係。
實例化Spring IoC容器很簡單。提供給ApplicationContext
構造函數的位置路徑 其實是資源字符串,它容許容器從各類外部資源(如本地文件系統,Java等)加載配置元數據CLASSPATH
。
ApplicationContext context = new ClassPathXmlApplicationContext(new String [] { 「services.xml」,「daos.xml」 });
![]() |
在瞭解Spring的IoC容器以後,您可能想了解更多關於Spring |
如下示例顯示服務層對象 (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」 / > <! - 此bean的其餘協做者和配置轉到此處 - > </ bean> <! - 更多的服務的bean定義在這裏 - > </bean>
如下示例顯示數據訪問對象 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.ibatis.SqlMapAccountDao」 > <! - 此bean的其餘協做者和配置轉到此處 - > </ bean> <bean id = 「itemDao」 class = 「org.springframework.samples.jpetstore.dao.ibatis.SqlMapItemDao」 > <! - 此bean的其餘協做者和配置轉到此處 - > </ bean> <! - 更多的數據訪問對象的bean定義在這裏 - > </bean>
在前面的例子中,服務層由類組成 PetStoreServiceImpl
,而類型SqlMapAccountDao
和SqlMapItemDao的兩個數據訪問對象基於iBatis 對象/關係映射框架。該property name
元素引用JavaBean屬性的名稱,該ref
元素引用另外一個bean定義的名稱。id和ref元素之間的這種聯繫表示協做對象之間的依賴關係。有關配置對象依賴關係的詳細信息,請參閱依賴關係。
讓bean定義跨越多個XML文件可能頗有用。一般,每一個單獨的XML配置文件都表明了架構中的邏輯層或模塊。
您可使用應用程序上下文構造函數從全部這些XML片斷中加載bean定義。這個構造函數有多個Resource
位置,如前一節所示。或者,使用一個或多個<import/>
元素來從另外一個或多個文件加載bean定義。例如:
<bean> <import resource = 「services.xml」 /> <import resource = 「resources / messageSource.xml」 /> <import resource = 「 / resources/ themeSource.xml」 /> <bean id = 「bean1」 class = 「...」 /> <bean id = 「bean2」 class = 「...」 /> </bean>
在前面的例子中,外部豆定義是從三個文件中,加載services.xml
, messageSource.xml
和 themeSource.xml
。全部位置路徑都與導入的定義文件相關,所以services.xml
必須位於與導入文件 相同的目錄或類路徑位置, messageSource.xml
並且 themeSource.xml
必須位於 resources
導入文件位置下方的位置。正如你所看到的,一個前導斜線被忽略,可是鑑於這些路徑是相對的,最好不要使用斜線。<beans/>
根據Spring Schema或DTD ,正在導入的文件(包括頂層元素)的內容必須是有效的XML bean定義。
![]() |
可能但不推薦使用相對的「../」路徑引用父目錄中的文件。這樣作會建立對當前應用程序外部的文件的依賴關係。特別是,不建議將此引用用於「classpath:」URL(例如「classpath:../ services.xml」),其中運行時解析過程選擇「最近」的類路徑根,而後查看其父目錄。類路徑配置更改可能會致使選擇不一樣的,不正確的目錄。 您始終可使用徹底限定的資源位置而不是相對路徑:例如,「file:C:/config/services.xml」或「classpath:/config/services.xml」。可是,請注意,您將應用程序的配置與特定絕對位置相關聯。一般最好保持這種絕對位置的間接性,例如經過在運行時根據JVM系統屬性解析的「$ {...}」佔位符。 |
這ApplicationContext
是高級工廠的接口,可以維護不一樣bean及其依賴項的註冊表。使用該方法T getBean(String name, Class<T> requiredType)
能夠檢索bean的實例。
在ApplicationContext
能夠讀取bean定義並訪問它們,以下所示:
// 建立並配置Bean ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"}); //檢索配置實例 PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class); //使用配置的實例 List userList = service.getUsernameList();
你getBean()
用來檢索你的bean的實例。該ApplicationContext
接口還有其餘一些檢索bean的方法,但理想狀況下,應用程序代碼不該該使用它們。事實上,你的應用程序代碼根本不該該調用該getBean()
方法,所以徹底不依賴於Spring API。例如,Spring與Web框架的集成爲各類Web框架類(如控制器和JSF託管的Bean)提供了依賴注入。