Spring的做用域以及RequestContextListener做用

1、配置方式 

在Spring2.0中除了之前的Singleton和Prototype外又加入了三個新的web做用域,分別爲request、session和global session,若是你想讓你的容器裏的某個bean擁有其中某種新的web做用域,java

除了在bean級上配置相應的scope屬性,還必須在容器級作一個額外的初始化配置。 web


<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>


若是你用的是早期版本的web容器(Servlet 2.4之前),那麼你要使用一個javax.servlet.Filter的實現。 spring

<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>/*</url-pattern>  
    </filter-mapping>  
...  
</web-app>

兩種方式完成徹底同樣的功能:基於LocalThread將HTTP request對象綁定到爲該請求提供服務的線程上。這使得具備request和session做用域的bean可以在後面的調用鏈中被訪問到。 

Request做用域 
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/> 


針對每次HTTP請求,Spring容器會根據loginAction bean定義建立一個全新的LoginAction bean實例,且該loginAction bean實例僅在當前HTTP request內有效,緩存

所以能夠根據須要放心的更改所建實例的內部狀態,而其餘請求中根據loginAction bean定義建立的實例,將不會看到這些特定於某個請求的狀態變化。當處理請求結束,request做用域的bean實例將被銷燬。 

Session做用域 服務器


<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/> session


針對某個HTTP Session,Spring容器會根據userPreferences bean定義建立一個全新的userPreferences bean實例,且該userPreferences bean僅在當前HTTP Session內有效。app

與request做用域同樣,你能夠根據須要放心的更改所建立實例的內部狀態,而別的HTTP Session中根據userPreferences建立的實例,將不會看到這些特定於某個HTTP Session的狀態變化。加密

當HTTP Session最終被廢棄的時候,在該HTTP Session做用域內的bean也會被廢棄掉。 

global session做用域 

<bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/> 

global session做用域相似於標準的HTTP Session做用域,不過它僅僅在基於portlet的web應用中才有意義。Portlet規範定義了全局Session的概念,url

它被全部構成某個portlet web應用的各類不一樣的portlet所共享。在global session做用域中定義的bean被限定於全局portlet Session的生命週期範圍內。 

請注意,假如你在編寫一個標準的基於Servlet的web應用,而且定義了一個或多個具備global session做用域的bean,系統會使用標準的HTTP Session做用域,而且不會引發任何錯誤 spa


2、爲何須要額外的配置RequestContextFilter 


也許會有一個疑問,已經經過ContextLoaderListener(或ContextLoaderServlet)將Web容器與Spring容器整合,爲何這裏還要用額外的RequestContextListener以支持Bean的另外3個做用域,

緣由是ContextLoaderListener實現ServletContextListener監聽器接口,而ServletContextListener只負責監聽Web容器的啓動和關閉的事件。RequestContextFilter實現ServletRequestListener監聽器接口,

該監聽器監聽HTTP請求事件,Web服務器接收的每次請求都會通知該監聽器。經過配置RequestContextFilter,Spring容器與Web容器結合的更加密切。 


3、做用域依賴問題 


若是將Web相關做用域的Bean注入到singleton或prototype的Bean中,這種狀況下,須要Spring AOP 


<bean name="car" class="com.demo.Car" scope="request">  
    <aop:scoped-proxy/>  
</bean>  
<bean id="boss" class="com.demo.Boss" >  
    <properrty name="car" ref="car" />  
</bean>



1. 什麼是scope?

    scope用來聲明IOC容器中的對象應該處的限定場景或者說該對象的存活空間,即在IOC容器在對象進入相應的scope以前,生成並裝配這些對象,在該對象再也不處於這些scope的限定以後,容器一般會銷燬這些對象。

2. scope分類

目前,scope的取值有5種。 

     在Spring 2.0以前,有singleton和prototype兩種;

    在Spring 2.0以後,爲支持web應用的ApplicationContext,推出另外三種:request,session和global session類型。

3. singleton (單一實例)

 一個容器中只存在一個實例,全部對該類型bean的依賴都引用這一單一實例,這就好像每一個幼兒園都會有一個滑梯同樣,這個幼兒園的小朋友共同使用這一個滑梯,而對於幼兒園容器來講,滑梯就是一個singleton的bean。

此外,singleton類型的bean定義,從容器啓動,到他第一次被請求而實例化開始,只要容器不銷燬或退出,該類型的bean的單一實例就會一直存活。

4. prototype

prototype的bean,容器在接受到該類型的對象的請求的時候,會每次都從新生成一個新的對象給請求方,雖然這種類型的對象的實例化以及屬性設置等工做都是由容器負責的,可是隻要準備完畢,而且對象實例返回給請求方以後,容器就不在擁有當前對象的引用,請求方須要本身負責當前對象後繼生命週期的管理工做,包括該對象的銷燬。也就是說,容器每次返回請求方該對象的一個新的實例以後,就由這個對象「自生自滅」了。

讓咱們繼續幼兒園的比喻,咱們今天要分蘋果了!將蘋果的bean的scope屬性聲明爲prototype,在每一個小朋友領取蘋果的時候,咱們都是發一個新的蘋果給他,發完以後,小朋友愛怎麼吃就怎麼吃,愛何時吃何時吃,可是注意吃完要把果核扔到垃圾箱哦!對於那些不能共享使用的對象類型,應該將其定義的scope設爲prototype,一般,聲明爲prototype的的bean,都是一些有狀態的,好比保存爲每一個顧客信息的對象。

5. request ,session和global session

他們只適用於web程序,一般是和XmlWebApplicationContext共同使用

5. 1 request:

<bean id ="requestPrecessor" class="...RequestPrecessor"   scope="request" />

Spring容器,即XmlWebApplicationContext 會爲每一個HTTP請求建立一個全新的RequestPrecessor對象,當請求結束後,,該對象的生命週期即告結束。當同時有10個HTTP請求進來的時候,容器會分別針對這10個請求建立10個全新的RequestPrecessor實例,且他們相互之間互不干擾,從不是很嚴格的意義上說,request能夠看作prototype的一種特例,除了場景更加具體以外,語意上差很少。

5.2 session:

對於web應用來講,放到session中最廣泛的就是用戶的登陸信息,對於這種放到session中的信息,咱們可使用以下形式的制定scope爲session:

<bean id ="userPreferences" class="...UserPreferences"   scope="session" />

Spring容器會爲每一個獨立的session建立屬於本身的全新的UserPreferences實例,他比request scope的bean會存活更長的時間,其餘的方面真是沒什麼區別

5.3 global session:

<bean id ="userPreferences" class="...UserPreferences"   scope="globalsession" />

global session只有應用在基於porlet的web應用程序中才有意義,他映射到porlet的global範圍的session,若是普通的servlet的web 應用中使用了這個scope,容器會把它做爲普通的session的scope對待。



spring IOC容器實例化Bean的方式有:

 

singleton            在spring IOC容器中僅存在一個Bean實例,Bean以單實例的方式存在.


prototype            每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時,至關於執行new XxxBean()的操做.


request               每次HTTP請求都會建立一個新的Bean,該做用域僅適用於webApplicationContext環境.


session               同一個HTTP session共享一個Bean,不一樣HTTP session使用不一樣的Bean,該做用域僅適用於webApplicationContext環境.


globalSession   同一個全局session共享一個Bean,通常用於portlet應用環境,該做用域僅適用於webApplicationContext環境.

 

 

在低版本的spring中,因爲只有兩個Bean做用域,因此採用singleton="true|false"的配置方 式,spring2.0爲了向後兼容,依舊支持這種配置方式.不過,spring2.0推薦採用新的配置方式:scope="<做用域類型>;"

-------------------------------------------------

singleton做用域


spring以容器的方式提供自然的單實例模式功能,任何POJO無須編寫特殊的代碼僅經過配置就能夠了.

注意:spring將Bean的默認做用域定爲singleton.

singleton例:

<bean id="car" class="com.baobaotao.scope.Car" scope="singleton"/>

<bean id="boss1" class="com.baobaotao.scope.Boss">

<property name="car" ref="car"/>

</bean>

Car Bean聲明爲singleton(由於默認是singleton,因此能夠不顯式指定).

在默認狀況下,spring的ApplicationContext容器在啓動時,自動實例化全部singleton的Bean並緩存於容器中.

雖然啓動時會花費一些時間,但帶來兩個好處:首先對Bean提早的實例化操做會及早發現一些潛在的配置問題.

其次Bean以緩存的方式保存,當運行時使用到該Bean時就無須再實例化了,加快了運行效率.若是用戶不但願在容

器啓動時提早實例化singleton的Bean,能夠經過lazy-init屬性進行控制:

 

<bean id="boos1" class="com.baobaotao.scope.Boss" lazy-init="true">

<property name="car" ref="car"/>

</bean>

lazy-init="true"的Bean在某些狀況下依舊會提早實例化:若是該Bean被其它須要提早實例化的Bean引用到,

spring也將忽略延遲實例化的設置.

-------------------------------------------------

prototype做用域

 

採用scope="prototype"指定非單實例做用域Bean,請看:

<bean id="car" class="com.baobaotao.scope.Car" scope="prototype"/>

<bean id="boss1" class="com.baobaotao.scope.Boss">

<property name="car" ref="car"/>

</bean>

<bean id="boss2" class="com.baobaotao.scope.Boss">

<property name="car" ref="car"/>

</bean>

boss1,boss2所引用的都是一個獨立的Car實例.

在默認狀況下,spring容器在啓動時不實例化prototype的Bean.此外,spring容器將prototype的Bean交給調用

者後,就再也不管理它的生命週期.

-------------------------------------------------

web應用環境相關的Bean做用域

 

若是用戶使用spring的webApplicationContext,則可使用另外3種Bean的做用域:request,session和globalSession.不過

在使用這些做用域以前,首先必須在web容器中進行一些額外的配置,在高版本的web容器中,則能夠利用HTTP請求監聽器進行配置:

<web-app>

...

<listener>

<listener-class>

org.springframework.web.context.request.RequestContextListener

</listener-class>

</listener>

...

</web-app>

細心的朋友可能有一個疑問:在介紹webApplicationContext初始化時,咱們已經經過ContextLoaderListener將web容器與

spring容器整合,爲何這裏又要引入一個額外的RequestContextListener以支持Bean的另外3個做用域呢?

在整合spring容器時使用ContextLoaderListener,它實現了ServletContextListener監聽器接口,ServletContextListener

只負責監聽web容器啓動和關閉的事件.而RequestContextListener實現ServletRequestListener監聽器接口,該監聽器監聽

HTTP請求事件,web服務器接收的每一次請求都會通知該監聽器.

spring容器啓動和關閉操做由web容器的啓動和關閉事件觸發,但若是spring容器中的Bean須要request,session,globalsession

做用域的支持,spring容器自己就必須得到web容器的HTTP請求事件,以HTTP請求的事件"驅動"Bean做用域的控制邏輯.

 

request做用域

顧名思義,request做用域的Bean對應一個HTTP請求和生命週期,考慮下面的配置:

<bean name="car" class="com.baobaotao.scope.Car" scope="request"/>

這樣,每次HTTP請求調用到car Bean時,spring容器建立一個新的Car Bean,請求處理完畢後,銷燬這個Bean.

 

session做用域

假設將以上car的做用域調整爲session類型:

<bean name="car" class="com.baobaotao.scope.Car" scope="session"/>

這樣配置後,car Bean的做用域橫跨整個HTTP session,session中全部HTTP請求都共享同一個Car Bean,當HTTP Session結束後,實例

才被銷燬.

 

globalSession做用域

下面的配置片段將car的做用域設置爲了globalSession:

<bean name="loginController" class="com.baobaotao.scope.Car" scope="globalSession"/>

globalSession做用域相似於session做用域,不過僅在portlet的web應用中使用.Portlet規範定義了全局Session概念,它被組成portlet

web應用的全部子portlet共享.若是不在Portlet web應用環境下,globalSession天然等價於session做有域了

相關文章
相關標籤/搜索