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做有域了

相关文章
相关标签/搜索