?
本文檔使用 PHP中文網(wǎng)手冊 發(fā)布
創(chuàng)建一個bean定義,其實質(zhì)是用該bean定義對應(yīng)的類來創(chuàng)建真正實例的“配方(recipe)”。把bean定義看成一個配方很有意義,它與class很類似,只根據(jù)一張“處方”就可以創(chuàng)建多個實例。
你不僅可以控制注入到對象中的各種依賴和配置值,還可以控制該對象的作用域。這樣你可以靈活選擇所建對象的作用域,而不必在Java Class級定義作用域。Spring Framework支持五種作用域(其中有三種只能用在基于web的Spring ApplicationContext
)。
內(nèi)置支持的作用域分列如下:
表?3.4.?Bean作用域
作用域 | 描述 |
---|---|
singleton |
在每個Spring IoC容器中一個bean定義對應(yīng)一個對象實例。 |
prototype |
一個bean定義對應(yīng)多個對象實例。 |
request |
在一次HTTP請求中,一個bean定義對應(yīng)一個實例;即每次HTTP請求將會有各自的bean實例,
它們依據(jù)某個bean定義創(chuàng)建而成。該作用域僅在基于web的Spring
|
session |
在一個HTTP |
global session |
在一個全局的HTTP |
當一個bean的作用域為singleton, 那么Spring IoC容器中只會存在一個共享的bean實例,并且所有對bean的請求,只要id與該bean定義相匹配,則只會返回bean的同一實例。
換言之,當把一個bean定義設(shè)置為singlton作用域時,Spring IoC容器只會創(chuàng)建該bean定義的唯一實例。這個單一實例會被存儲到單例緩存(singleton cache)中,并且所有針對該bean的后續(xù)請求和引用都將返回被緩存的對象實例。
請注意Spring的singleton bean概念與“四人幫”(GoF)模式一書中定義的Singleton模式是完全不同的。經(jīng)典的GoF Singleton模式中所謂的對象范圍是指在每一個ClassLoader
中指定class創(chuàng)建的實例有且僅有一個。把Spring的singleton作用域描述成一個container
對應(yīng)一個bean實例最為貼切。亦即,假如在單個Spring容器內(nèi)定義了某個指定class的bean,那么Spring容器將會創(chuàng)建一個且僅有一個由該bean定義指定的類實例。Singleton作用域是Spring中的缺省作用域。要在XML中將bean定義成singleton,可以這樣配置:
<bean id="accountService" class="com.foo.DefaultAccountService"/> <!-- the following is equivalent, though redundant (singleton scope is the default); usingspring-beans-2.0.dtd
--> <bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/> <!-- the following is equivalent and preserved for backward compatibility inspring-beans.dtd
--> <bean id="accountService" class="com.foo.DefaultAccountService" singleton="true"/>
Prototype作用域的bean會導致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調(diào)用容器的getBean()
方法)時都會創(chuàng)建一個新的bean實例。根據(jù)經(jīng)驗,對有狀態(tài)的bean應(yīng)該使用prototype作用域,而對無狀態(tài)的bean則應(yīng)該使用singleton作用域。
下圖演示了Spring的prototype作用域。請注意,通常情況下,DAO不會被配置成prototype,因為DAO通常不會持有任何會話狀態(tài),因此應(yīng)該使用singleton作用域。
要在XML中將bean定義成prototype,可以這樣配置:
<!-- usingspring-beans-2.0.dtd
--> <bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/> <!-- the following is equivalent and preserved for backward compatibility inspring-beans.dtd
--> <bean id="accountService" class="com.foo.DefaultAccountService" singleton="false"/>
對于prototype作用域的bean,有一點非常重要,那就是Spring不能對一個prototype bean的整個生命周期負責:容器在初始化、配置、裝飾或者是裝配完一個prototype實例后,將它交給客戶端,隨后就對該prototype實例不聞不問了。不管何種作用域,容器都會調(diào)用所有對象的初始化生命周期回調(diào)方法。但對prototype而言,任何配置好的析構(gòu)生命周期回調(diào)方法都將不會被調(diào)用。清除prototype作用域的對象并釋放任何prototype bean所持有的昂貴資源,都是客戶端代碼的職責。(讓Spring容器釋放被prototype作用域bean占用資源的一種可行方式是,通過使用bean的后置處理器,該處理器持有要被清除的bean的引用。)
談及prototype作用域的bean時,在某些方面你可以將Spring容器的角色看作是Java new
操作的替代者。任何遲于該時間點的生命周期事宜都得交由客戶端來處理。(在第?3.5.1?節(jié) “生命周期回調(diào)”一節(jié)中會進一步講述Spring容器中的bean生命周期。)
當使用依賴于prototype bean的singleton-scoped bean時,請注意依賴是在實例化時處理的。這也就是說,如果要把一個prototype-scoped bean注入到singleton-scoped bean,實際上只是實例化一個新的prototype bean注入到 singleton bean...但這是全部。這種情況下,singleton-scoped bean獲得的prototype實例是唯一的。
然而,你可能需要在運行期讓singleton-scoped bean每次都獲得prototype-scoped bean的新實例。在這種情況下,只將prototype-scoped bean注入到你的singleton bean中是沒有用的,因為正如上文所說的,僅僅在當Spring容器實例化singleton bean并且處理注入的依賴時,生成唯一實例。如果你需要在運行期一次又一次的生成(prototype) bean的新實例,你可以參考第?3.3.7?節(jié) “方法注入”
如果你在bean定義文件中引用'spring-beans.dtd'
DTD,
要顯式說明bean的生命周期作用域你必須使用"singleton
"屬性(記住singleton生命周期作用域是默認的)。
如果引用的是'spring-beans-2.0.dtd'
DTD或者是Spring 2.0 XSD schema,
那么需要使用"scope
"屬性(因為"singleton
"屬性被刪除了,
新的DTD和XSD文件使用"scope
"屬性)
簡單地說,如果你用"singleton
"屬性那么就必須在那個文件里
引用'spring-beans.dtd'
DTD。
如果你用"scope
"屬性那么必須 在那個文件里引用'spring-beans-2.0.dtd'
DTD 或'spring-beans-2.0.xsd'
XSD。
其他作用域,即request
、session
以及global session
僅在基于web的應(yīng)用中使用(不必關(guān)心你所采用的是什么web應(yīng)用框架)。
下面介紹的作用域僅僅在使用基于web的Spring ApplicationContext
實現(xiàn)(如XmlWebApplicationContext
)時有用。
如果在普通的Spring IoC容器中,比如像XmlBeanFactory
或ClassPathXmlApplicationContext
,
嘗試使用這些作用域,你將會得到一個IllegalStateException
異常(未知的bean作用域)。
要使用request
、session
和
global session
作用域的bean(即具有web作用域的bean),
在開始設(shè)置bean定義之前,還要做少量的初始配置。請注意,假如你只想要“常規(guī)的”作用域,(singleton和prototype),就不需要這一額外的設(shè)置。
在目前的情況下,根據(jù)你的特定servlet環(huán)境,有多種方法來完成這一初始設(shè)置...
如果你用Spring Web MVC,即用SpringDispatcherServlet
或DispatcherPortlet
來處理請求,則不需要做特別的配置:DispatcherServlet
和
DispatcherPortlet
已經(jīng)處理了所有有關(guān)的狀態(tài)
當使用了Spring's DispatcherServlet以外的Servlet 2.4及以上的Web容器時(如使用JSF或Struts),你需要在Web應(yīng)用的'web.xml'
文件中增加 javax.servlet.ServletRequestListener
定義
<web-app> ... <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> ... </web-app>
如果你用的是早期版本的web容器(Servlet 2.4以前的版本),那么你要使用一個javax.servlet.Filter
的實現(xiàn)。請看下面的web.xml配置片段:
<web-app> .. <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>*Context.xml(WEB-INF文件夾及子文件夾下的以"Context.xml"結(jié)尾的文件)。
ContextLoaderServlet
同ContextLoaderListener
一樣使用'contextConfigLocation'
參數(shù)。