?
Ce document utilise Manuel du site Web PHP chinois Libérer
在Spring中,那些組成你應用程序的主體(backbone)及由Spring IoC容器所管理的對象,被稱之為bean。 簡單地講,bean就是由Spring容器初始化、裝配及管理的對象,除此之外,bean就與應用程序中的其他對象沒有什么區(qū)別了。 而bean定義以及bean相互間的依賴關系將通過配置元數(shù)據(jù)來描述。
org.springframework.beans.factory.BeanFactory
是Spring IoC容器的實際代表者,IoC容器負責容納此前所描述的bean,并對bean進行管理。
在Spring中,BeanFactory
是IoC容器的核心接口。
它的職責包括:實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。
Spring為我們提供了許多易用的BeanFactory
實現(xiàn),
XmlBeanFactory
就是最常用的一個。該實現(xiàn)將以XML方式描述組成應用的對象
以及對象間的依賴關系。XmlBeanFactory
類將獲取此XML配
置元數(shù)據(jù),并用它來構建一個完全可配置的系統(tǒng)或應用。
Spring IoC 容器
從上圖可以看到,Spring IoC容器將讀取配置元數(shù)據(jù); 并通過它對應用中各個對象進行實例化、配置以及組裝。通常情況下我們使用簡單直觀 的XML來作為配置元數(shù)據(jù)的描述格式。在XML配置元數(shù)據(jù)中我們可以對那些我們希望通過 Spring IoC容器管理的bean進行定義。
到目前為止,基于XML的元數(shù)據(jù)是最常用到的配置元數(shù)據(jù)格式。然而,它并 不是唯一的描述格式。Spring IoC容器在這一點上是 完全開放的。由于采用基于XML的配置元數(shù)據(jù)格式非常簡單, 因此 本章節(jié)的大部分內(nèi)容將采用該格式來說明Spring IoC容器的關鍵概念和功能
同時你也可以在第?3.11?節(jié) “基于注解(Annotation-based)的配置”這一節(jié)中 看到Spring容器支持的另一種元數(shù)據(jù)格式的詳細內(nèi)容。
在大多數(shù)的應用程序中,并不需要用顯式的代碼去實例化一個或多個的Spring IoC
容器實例。例如,在web應用程序中,我們只需要在web.xml
中添加
(大約)8 行簡單的XML描述符即可(參見第?3.8.5?節(jié) “ApplicationContext
在WEB應用中的實例化”)。
Spring IoC容器至少包含一個bean定義,但大多數(shù)情況下會有多個bean定義。當使用
基于XML的配置元數(shù)據(jù)時,將在頂層的<beans/>
元素中配置一個
或多個<bean/>
元素。
bean定義與應用程序中實際使用的對象一一對應。通常情況下bean的定義包括:服務
層對象、數(shù)據(jù)訪問層對象(DAO)、類似Struts Action
的
表示層對象、Hibernate SessionFactory
對象、JMS
Queue
對象等等。通常bean的定義并不與容器中的領域
對象相同,因為領域?qū)ο蟮膭?chuàng)建和加載必須依賴具體的DAO和業(yè)務邏輯。.
以下是一個基于XML的配置元數(shù)據(jù)的基本結(jié)構:
<?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-2.5.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>
Spring IoC容器的實例化非常簡單,如下面的例子:
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] {"services.xml", "daos.xml"});
// an ApplicationContext
is also a BeanFactory
(via inheritance)
BeanFactory factory = context;
將XML配置文件分拆成多個部分是非常有用的。為了加載多個XML文件生成一個 ApplicationContext實例,可以將文件路徑作為字符串數(shù)組傳給ApplicationContext構造器 。而bean factory將通過調(diào)用bean defintion reader從多個文件中讀取bean定義。
通常情況下,Spring團隊傾向于上述做法,因為這樣各個配置并不會查覺到它們
與其他配置文件的組合。另外一種方法是使用一個或多個的<import/>
元素
來從另外一個或多個文件加載bean定義。所有的<import/>
元素必
須在<bean/>
元素之前完成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>
在上面的例子中,我們從3個外部文件:services.xml
、
messageSource.xml
及themeSource.xml
來加載bean定義。這里采用的都是相對路徑,因此,此例中的services.xml
一定要與導入文件放在同一目錄或類路徑,而messageSource.xm
l
和themeSource.xml
的文件位置必須放在導入文件所
在目錄下的resources
目錄中。正如你所看到的那樣,開頭的斜杠
‘/’實際上可忽略。因此不用斜杠‘/’可能會更好一點。根據(jù)Spring XML配置文件的
Schema(或DTD),被導入文件必須是完全有效的XML bean定義文件,且根節(jié)點必須為
<beans/>
元素。
Spring IoC容器將管理一個或多個bean,這些bean
將通過配置文件中的bean定義被創(chuàng)建(在XML格式中為<bean/>
元素)。
在容器內(nèi)部,這些bean定義由BeanDefinition
對象來表示,該定義將包含以下信息:
全限定類名:這通常就是已定義bean的實際實現(xiàn)類。
bean行為的定義,這些定義將決定bean在容器中的行為(作用域、生命周期回調(diào)等等)
對其他bean的引用,這些引用bean也可以稱之為協(xié)作bean(collaborators) 或依賴bean(dependencies).
創(chuàng)建bean實例時的其他配置設置。比如使用bean來定義連接池,可以通過屬性或者構 造參數(shù)指定連接數(shù),以及連接池大小限制等。
上述內(nèi)容直接被翻譯為每個bean定義包含的一組properties。下面的表格列出了部分 內(nèi)容的詳細鏈接:
表?3.1.?bean定義
名稱 | 鏈接 |
---|---|
class |
第?3.2.3.2?節(jié) “實例化bean” |
name |
第?3.2.3.1?節(jié) “bean的命名” |
scope |
第?3.4?節(jié) “Bean的作用域” |
constructor arguments |
第?3.3.1?節(jié) “注入依賴” |
properties |
第?3.3.1?節(jié) “注入依賴” |
autowiring mode |
第?3.3.5?節(jié) “自動裝配(autowire)協(xié)作者” |
dependency checking mode |
第?3.3.6?節(jié) “依賴檢查” |
lazy-initialization mode |
第?3.3.4?節(jié) “延遲初始化bean” |
initialization method |
第?3.5.1.1?節(jié) “初始化回調(diào)” |
destruction method |
第?3.5.1.2?節(jié) “析構回調(diào)” |
除了通過bean定義來描述要創(chuàng)建的指定bean的屬性之外,某些
BeanFactory
的實現(xiàn)也允許將那些非BeanFactory創(chuàng)建的、已有的用戶
對象注冊到容器中,比如使用DefaultListableBeanFactory
的registerSingleton(..)
方法。不過大多數(shù)應用還是采用
元數(shù)據(jù)定義為主。
每個bean都有一個或多個id
(或稱之為標識符或名稱,在術語
上可以理解成一回事)。這些id
在當前IoC容器中必須唯一。如果
一個bean有多個id,那么其他的id在本質(zhì)上將被認為是別名。
當使用基于XML的配置元數(shù)據(jù)時,將通過id
或
name
屬性來指定bean標識符。id
屬性具有唯一性,
而且是一個真正的XML ID屬性,因此其他xml元素在引用該id時,可以利用XML解析器的
驗證功能。通常情況下最好為bean指定一個id。盡管XML規(guī)范規(guī)定了XML ID命名的有效
字符,但是bean標識符的定義不受該限制,因為除了使用指定的XML字符來作為id,還可
以為bean指定別名,要實現(xiàn)這一點可以在name
屬性中使用逗號、
冒號或者空格將多個id分隔。
值得注意的是,為一個bean提供一個name并不是必須的,如果沒有指定,那么容 器將為其生成一個惟一的name。對于不指定name屬性的原因我們會在后面介紹(比如 內(nèi)部bean就不需要)。
在對bean進行定義時,除了使用id
屬性來指定名稱
之外,為了提供多個名稱,需要通過name
屬性來加以指定
。而所有的這些名稱都指向同一個bean,在某些情況下提供別名非常有用,比如
為了讓應用的每一個組件能更容易的對公共組件進行引用。
然而,在定義bean時就指定所有的別名并不是總是恰當?shù)?。有時我們期望
能在當前位置為那些在別處定義的bean引入別名。在XML配置文件中,可用
<alias/>
元素來完成bean別名的定義。如:
<alias name="fromName" alias="toName"/>
這里如果在容器中存在名為fromName
的bean定義,
在增加別名定義之后,也可以用toName
來引用。
考慮一個更為具體的例子,組件A在XML配置文件中定義了一個名為 componentA-dataSource的DataSource bean。但組件B卻想在其XML文件中 以componentB-dataSource的名字來引用此bean。而且在主程序MyApp的XML配 置文件中,希望以myApp-dataSource的名字來引用此bean。最后容器加載三個 XML文件來生成最終的ApplicationContext,在此情形下,可通過在MyApp XML 文件中添加下列alias元素來實現(xiàn):
<alias name="componentA-dataSource" alias="componentB-dataSource"/> <alias name="componentA-dataSource" alias="myApp-dataSource" />
這樣一來,每個組件及主程序就可通過唯一名字來引用同一個數(shù)據(jù)源而互不干擾。
從本質(zhì)上來說,bean定義描述了如何創(chuàng)建一個或多個對象實例。當需要的時候, 容器會從bean定義列表中取得一個指定的bean定義,并根據(jù)bean定義里面的配置元數(shù)據(jù) 使用反射機制來創(chuàng)建(或取得)一個實際的對象。
當采用XML描述配置元數(shù)據(jù)時,將通過<bean/>
元素的
class
屬性來指定實例化對象的類型。class
屬性 (對應BeanDefinition
實例的
Class
屬性)通常是必須的(不過也有兩種例外的情形,見
第?3.2.3.2.3?節(jié) “使用實例工廠方法實例化”和
第?3.6?節(jié) “bean定義的繼承”)。class屬性主要有兩種用途
:在大多數(shù)情況下,容器將直接通過反射調(diào)用指定類的構造器來創(chuàng)建bean(這有點類似于
在Java代碼中使用new操作符);在極少數(shù)情況下,容器將調(diào)用
類的靜態(tài)
工廠方法來創(chuàng)建bean實例,class
屬性將用來指定實際具有靜態(tài)
工廠方法的類(至于調(diào)用靜態(tài)工廠
方法創(chuàng)建的對象類型是當前class還是其他的class則無關緊要)。
當采用構造器來創(chuàng)建bean實例時,Spring對class并沒有特殊的要求, 我們通常使用的class都適用。也就是說,被創(chuàng)建的類并不需要實現(xiàn)任何特定的 接口,或以特定的方式編碼,只要指定bean的class屬性即可。不過根據(jù)所采用 的IoC類型,class可能需要一個默認的空構造器。
此外,IoC容器不僅限于管理JavaBean,它可以管理任意 的類。不過大多數(shù)使用Spring的人喜歡使用實際的JavaBean(具有默認的(無參)構造器 及setter和getter方法),但在容器中使用非bean形式(non-bean style)的類也是可 以的。比如遺留系統(tǒng)中的連接池,很顯然它與JavaBean規(guī)范不符,但Spring也能管理它。
當使用基于XML的元數(shù)據(jù)配置文件,可以這樣來指定bean類:
<bean id="exampleBean" class="examples.ExampleBean"/> <bean name="anotherExample" class="examples.ExampleBeanTwo"/>
給構造函數(shù)指定參數(shù)以及為bean實例設置屬性將在隨后的 部分中談及。
當采用靜態(tài)工廠方法創(chuàng)建bean時,除了需要指定class
屬性外,還需要通過factory-method
屬性來指定創(chuàng)建bean實例
的工廠方法。Spring將調(diào)用此方法(其可選參數(shù)接下來介紹)返回實例對象,就此而言,
跟通過普通構造器創(chuàng)建類實例沒什么兩樣。
下面的bean定義展示了如何通過工廠方法來創(chuàng)建bean實例。注意,此定義并
未指定返回對象的類型,僅指定該類包含的工廠方法。在此例中,
createInstance()
必須是一個static方法。
<bean id="exampleBean" class="examples.ExampleBean2" factory-method="createInstance"/>
給工廠方法指定參數(shù)以及為bean實例設置屬性將在隨后的部份中談及。
與
使用靜態(tài)工廠方法實例化類似,用來進行實例化的非靜態(tài)實例工廠方法位
于另外一個bean中,容器將調(diào)用該bean的工廠方法來創(chuàng)建一個新的bean實例。為使
用此機制,class
屬性必須為空,而factory-bean
屬性必須指定為當前(或其祖先)容器中包含工廠方法的bean的名稱,而該
工廠bean的工廠方法本身必須通過factory-method
屬性來設定。
<!-- the factory bean, which contains a method called createInstance()
-->
<bean id="serviceLocator" class="com.foo.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="exampleBean"
factory-bean="serviceLocator"
factory-method="createInstance"/>
雖然設置bean屬性 的機制仍然在這里被提及,但隱式的做法是由工廠bean自己來管理以及通過依 賴注入(DI)來進行配置。
Spring文檔中的factory bean指的是配置在Spring容器中通過使用
實例
或
靜態(tài)工廠方法創(chuàng)建對象的一種bean。而文檔中的FactoryBean
(注意首字母大寫)指的是Spring特有的
FactoryBean
。
從本質(zhì)上講,BeanFactory
僅僅只是一個
維護bean定義以及相互依賴關系的高級工廠接口。通過BeanFactory
我們可以訪問bean定義。下面的例子創(chuàng)建了一個bean工廠,此工廠
將從xml文件中讀取bean定義:
Resource res = new FileSystemResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(res);
基本上就這些了,接著使用getBean(String)
方法就可以取得bean的實例;BeanFactory
提供的方法極其簡單。 BeanFactory
接口提供
了非常多的方法,但是對于我們的應用來說,最好永遠不要調(diào)用它們,當然也包括
使用getBean(String)
方法,這樣可以避免我們對
Spring API的依賴。