| 作用域 | 描述 |
|---|---|
singleton | 在每個(gè)Spring IoC容器中一個(gè)bean定義對(duì)應(yīng)一個(gè)對(duì)象實(shí)例。 |
prototype | 一個(gè)bean定義對(duì)應(yīng)多個(gè)對(duì)象實(shí)例。 |
request | 在一次HTTP請(qǐng)求中,一個(gè)bean定義對(duì)應(yīng)一個(gè)實(shí)例;即每次HTTP請(qǐng)求將會(huì)有各自的bean實(shí)例,它們依據(jù)某個(gè)bean定義創(chuàng)建而成。該作用域僅在基于web的Spring |
在一個(gè)HTTP | |
global session | 在一個(gè)全局的HTTP |
當(dāng)一個(gè)bean的作用域?yàn)閟ingleton, 那么Spring IoC容器中只會(huì)存在一個(gè)共享的bean實(shí)例,并且所有對(duì)bean的請(qǐng)求,只要id與該bean定義相匹配,則只會(huì)返回bean的同一實(shí)例。
換言之,當(dāng)把一個(gè)bean定義設(shè)置為singlton作用域時(shí),Spring IoC容器只會(huì)創(chuàng)建該bean定義的唯一實(shí)例。這個(gè)單一實(shí)例會(huì)被存儲(chǔ)到單例緩存(singleton cache)中,并且所有針
對(duì)該bean的后續(xù)請(qǐng)求和引用都將返回被緩存的對(duì)象實(shí)例。
Prototype作用域Prototype作用域的bean會(huì)導(dǎo)致在每次對(duì)該bean請(qǐng)求(將其注入到另一個(gè)bean中,或者以程序的方式調(diào)用容器的getBean()方法)時(shí)都會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。根據(jù)經(jīng)驗(yàn),對(duì)所
有有狀態(tài)的bean應(yīng)該使用prototype作用域,而對(duì)無(wú)狀態(tài)的bean則應(yīng)該使用singleton作用域。
其他作用域
request、session以及global session僅在基于web的應(yīng)用中使用(不必關(guān)心你所采用的是什么web應(yīng)用框架)。
注意
下面介紹的作用域僅僅在使用基于web的SpringApplicationContext實(shí)現(xiàn)(如xmlWebApplicationContext)時(shí)有用。如果在普通的Spring IoC容器中,比如像XmlBeanFactory
或ClassPathXmlApplicationContext,嘗試使用這些作用域,你將會(huì)得到一個(gè)IllegalStateException異常(未知的bean作用域)。
初始化web配置
要使用request、session和global session作用域的bean(即具有web作用域的bean),在開(kāi)始設(shè)置bean定義之前,還要做少量的初始配置。請(qǐng)注意,假如你只想要“常規(guī)的”作用域,也就是singleton和prototype,就不需要這一額外的設(shè)置。
在目前的情況下,根據(jù)你的特定servlet環(huán)境,有多種方法來(lái)完成這一初始設(shè)置。如果你使用的是Servlet 2.4及以上的web容器,那么你僅需要在web應(yīng)用的XML聲明文件web.xml中增加下述ContextListener即可
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
如果你用的是早期版本的web容器(Servlet 2.4以前),那么你要使用一個(gè)javax.servlet.Filter的實(shí)現(xiàn)。請(qǐng)看下面的web.xml配置片段:
<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>/*</url-pattern> </filter-mapping>
RequestContextListener和RequestContextFilter兩個(gè)類(lèi)做的都是同樣的工作:將HTTP request對(duì)象綁定到為該請(qǐng)求提供服務(wù)的Thread。這使得具有request和session作用域的bean能夠在后面的調(diào)用鏈中被訪(fǎng)問(wèn)到。
針對(duì)每次HTTP請(qǐng)求,Spring容器會(huì)根據(jù)loginActionbean定義創(chuàng)建一個(gè)全新的LoginActionbean實(shí)例,且該loginActionbean實(shí)例僅在當(dāng)前HTTP request內(nèi)有效,因此可以根據(jù)需要放心的更改所建實(shí)例的內(nèi)部狀態(tài),而其他請(qǐng)求中根據(jù)loginActionbean定義創(chuàng)建的實(shí)例,將不會(huì)看到這些特定于某個(gè)請(qǐng)求的狀態(tài)變化。當(dāng)處理請(qǐng)求結(jié)束,request作用域的bean實(shí)例將被銷(xiāo)毀。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
針對(duì)某個(gè)HTTPSession,Spring容器會(huì)根據(jù)userPreferencesbean定義創(chuàng)建一個(gè)全新的userPreferencesbean實(shí)例,且該userPreferencesbean僅在當(dāng)前HTTPSession內(nèi)有效。與request作用域一樣,你可以根據(jù)需要放心的更改所創(chuàng)建實(shí)例的內(nèi)部狀態(tài),而別的HTTPSession中根據(jù)userPreferences創(chuàng)建的實(shí)例,將不會(huì)看到這些特定于某個(gè)HTTPSession的狀態(tài)變化。當(dāng)HTTPSession最終被廢棄的時(shí)候,在該HTTPSession作用域內(nèi)的bean也會(huì)被廢棄掉。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/>
global session作用域類(lèi)似于標(biāo)準(zhǔn)的HTTPSession作用域,不過(guò)它僅僅在基于portlet的web應(yīng)用中才有意義。Portlet規(guī)范定義了全局Session的概念,它被所有構(gòu)成某個(gè)portlet web應(yīng)用的各種不同的portlet所共享。在global session作用域中定義的bean被限定于全局portletSession的生命周期范圍內(nèi)。
請(qǐng)注意,假如你在編寫(xiě)一個(gè)標(biāo)準(zhǔn)的基于Servlet的web應(yīng)用,并且定義了一個(gè)或多個(gè)具有global session作用域的bean,系統(tǒng)會(huì)使用標(biāo)準(zhǔn)的HTTPSession作用域,并且不會(huì)引起任何錯(cuò)誤。
能夠在HTTP request或者Session(甚至自定義)作用域中定義bean固然很好,但是Spring IoC容器除了管理對(duì)象(bean)的實(shí)例化,同時(shí)還負(fù)責(zé)協(xié)作者(或者叫依賴(lài))的實(shí)例化。如果你打算將一個(gè)Http request范圍的bean注入到另一個(gè)bean中,那么需要注入一個(gè)AOP代理來(lái)替代被注入的作用域bean。也就是說(shuō),你需要注入一個(gè)代理對(duì)象,該對(duì)象具有與被代理對(duì)象一樣的公共接口,而容器則可以足夠智能的從相關(guān)作用域中(比如一個(gè)HTTP request)獲取到真實(shí)的目標(biāo)對(duì)象,并把方法調(diào)用委派給實(shí)際的對(duì)象。
<aop:scoped-proxy/>不能和作用域?yàn)?code>singleton或prototype的bean一起使用。為singleton bean創(chuàng)建一個(gè)scoped proxy將拋出BeanCreationException異常。
讓我們看一下將相關(guān)作用域bean作為依賴(lài)的配置,配置并不復(fù)雜(只有一行),但是理解“為何這么做”以及“如何做”是很重要的。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> <aop:scoped-proxy/> </bean> <bean id="userService" class="com.foo.SimpleUserService"> <property name="userPreferences" ref="userPreferences"/> </bean>
在XML配置文件中,要?jiǎng)?chuàng)建一個(gè)作用域bean的代理,只需要在作用域bean定義里插入一個(gè)<aop:scoped-proxy/>子元素即可(你可能還需要在classpath里包含CGLIB庫(kù),這樣容器就能夠?qū)崿F(xiàn)基于class的代理;還可能要使用基于XSD的配置)。上述XML配置展示了“如何做”,現(xiàn)在討論“為何這么做”。在作用域?yàn)?code>request、session以及globalSession的bean定義里,為什么需要這個(gè)<aop:scoped-proxy/>元素呢?下面我們從去掉<aop:scoped-proxy/>元素的XML配置開(kāi)始說(shuō)起:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>
從上述配置中可以很明顯的看到singleton beanuserManager被注入了一個(gè)指向HTTPSession作用域beanuserPreferences的引用。singletonuserManagerbean會(huì)被容器僅實(shí)例化一次,并且其依賴(lài)(userPreferencesbean)也僅被注入一次。這意味著,userManager在理論上只會(huì)操作同一個(gè)userPreferences對(duì)象,即原先被注入的那個(gè)bean。而注入一個(gè)HTTPSession作用域的bean作為依賴(lài),有違我們的初衷。因?yàn)槲覀兿胍闹皇且粋€(gè)userManager對(duì)象,在它進(jìn)入一個(gè)HTTPSession生命周期時(shí),我們希望去使用一個(gè)HTTPSession的userPreferences對(duì)象。
當(dāng)注入某種類(lèi)型對(duì)象時(shí),該對(duì)象實(shí)現(xiàn)了和UserPreferences類(lèi)一樣的公共接口(即UserPreferences實(shí)例)。并且不論我們底層選擇了何種作用域機(jī)制(HTTP request、Session等等),容器都會(huì)足夠智能的獲取到真正的UserPreferences對(duì)象,因此我們需要將該對(duì)象的代理注入到userManagerbean中, 而userManagerbean并不會(huì)意識(shí)到它所持有的是一個(gè)指向UserPreferences引用的代理。在本例中,當(dāng)UserManager實(shí)例調(diào)用了一個(gè)使用UserPreferences對(duì)象的方法時(shí),實(shí)際調(diào)用的是代理對(duì)象的方法。隨后代理對(duì)象會(huì)從HTTPSession獲取真正的UserPreferences對(duì)象,并將方法調(diào)用委派給獲取到的實(shí)際的UserPreferences對(duì)象。
自定義作用域
詳情百度,知道有這么個(gè)東西就行了
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注