ContextLoaderListener與RequestContextListener配置問題


轉自:https://blog.csdn.net/yyqhwr/article/details/83381447

SSH2、SSM等web應用開發框架的配置過程中,因為都要用到spring,所以,往往我們首先都要配置Spring。Spring配置過程中要考慮兩個監聽器:

ContextLoaderListener與RequestContextListener。這兩個監聽器是什么意思?是不是兩個監聽器都需要配置?它們之間到底存在什么關系?下面,根據實驗和網上的資料解釋,我將匯總如下:

ContextLoaderListener與RequestContextListener

ContextLoaderListener

ContextLoaderListener extends ContextLoader implements ServletContextListener。

ServletContextListener extends EventListener。
ServletContextListener只負責監聽Web容器的啟動和關閉的事件。

ContextLoaderListener(或ContextLoaderServlet)將Web容器與spring容器進行整合。

這是使用Spring 必須配置 的:

  <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 
  • 1
  • 2
  • 3

Spring配置文件的聲明:

<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>

如果沒有顯式聲明,則 系統默認 在WEB-INF/applicationContext.xml。

在一個團隊使用Spring的實際項目中,應該需要多個Spring的配置文件,如何使用和交叉引用的問題:
如果想裝入多個配置文件,可以用逗號作分隔符,如:

<context-param> <param-name>contextConfigLocation</param-name> <param-value>applicationContext-database.xml,applicationContext.xml</param-value> </context-param>
  • 1
  • 2
  • 3

多個配置文件里的交叉引用可以用ref的external或bean解決,例如:

applicationContext.xml

<bean id="userService" class="domain.user.service.impl.UserServiceImpl"> <property name="dbbean"> <ref bean="dbBean"/> </property> </bean>
  • 1
  • 2
  • 3
  • 4

dbBean在applicationContext-database.xml中。

RequestContextListener

RequestContextListener implements ServletRequestListener

ServletRequestListener extends EventListener
ServletRequestListener監聽HTTP請求事件,Web服務器接收的每次請求都會通知該監聽器。

RequestContextListener將Spring容器與Web容器結合的更加密切。這是可選配置,並且后者與scope=”request”搭配使用:

<listener>
  <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
  • 1
  • 2
  • 3

兩者區別

ContextLoaderListener(或ContextLoaderServlet)將Web容器與spring容器整合。RequestContextListener將Spring容器與Web容器結合的更加密切。
前者為必選配置,后者為可選配置,並且后者與scope=”request”搭配使用。

詳細案例解析

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>
  • 1
  • 2
  • 3
  • 4

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>
  • 1
  • 2

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

細心的朋友可能有一個疑問:在介紹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"/>
  • 1

這樣,每次HTTP請求調用到car Bean時,spring容器創建一個新的Car Bean,請求處理完畢后,銷毀這個Bean。

session作用域

假設將以上car的作用域調整為session類型:

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

這樣配置后,car Bean的作用域橫跨整個HTTP session,session中所有HTTP請求都共享同一個Car Bean,當HTTP Session結束后,實例才被銷毀.

globalSession作用域

下面的配置片斷將car的作用域設置為了globalSession:

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

globalSession作用域類似於session作用域,不過僅在portlet的web應用中使用。Portlet規范定義了全局Session概念,它被組成portlet web應用的所有子portlet共享。如果不在Portlet web應用環境下,globalSession自然等價於session作有域了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM