当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定作用域。Spring支持如下5种作用域:
Spring支持的作用域
作用域 | 说明 |
singleton | 单例模式,在整个Spring IOC容器中,使用singleton定义的Bean将只有一个实例。 |
prototype | 原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。 |
request | 对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的 Bean实例。只有在Web应用中使用Spring时,该作用域才真正有效。 |
session | 对于每次HTTP Session,使用session定义的Bean都将产生一个新实例,即每次HTTP Session都将产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才真正有效。 |
global session | 每个全局的HTTP Session对应一个Bean实例。典型的情况下,仅在使用portlet context的时候有效。 只有在Web应用中使用Spring时,该作用域才真正有效。 |
比较常用的是singleton和prototype两种作用域。对于
singleton 作用域的Bean,每次请求该Bean都将获得相同的实例,容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成
prototype 作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new关键字创建Bean实例,一旦创建成功,容器不再跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此除非必要,否则尽量避免将Bean设置成prototype作用域。
<bean id="p1" class="com.Person"/>
<bean id="p2" class="com.Person" scope="prototype"/>
public class Test {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("bean.xml");
System.out.println(ctx.getBean("p1")==ctx.getBean("p1"));//true
System.out.println(ctx.getBean("p2")==ctx.getBean("p2"));//false
}
}
对于 request
<bean id="loginAction" class="org.struts2.LoginAction" scope="request"/>
针对每次HTTP请求,Spring容器会根据loginAction Bean定义创建一个全新的LoginAction Bean实例,且该loginAction Bean实例仅在当前HTTP Request内有效。因此如果程序需要,完全可以自由更改Bean实例的内部状态;其他请求所获得的loginAction Bean实例无法感觉到这种内部状态的改变。当处理请求结束时,request作用域的Bean实例将被销毁。
session 作用域与request作用域完全类似,区别在于:request作用域的Bean对于每次HTTP请求有效,而session作用域的Bean则对于每次HTTP Session有效。
request和session作用域只在Web应用中才有效,并且必须在Web应用中增加额外配置才会生效。有两种方式:采用Listener配置或采用Filter配置。
① Listener配置:
当使用支持Servlet2.4及以上规范的Web容器时,我们可以在Web应用的web.xml文件中增加如下Listener配置,该Listener配置负责为request作用域生效。
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
如果使用了只支持Servlet2.4以前规范的Web容器,则该容器不支持Listener规范,故无法使用这种配置方式,只能改为使用Filter配置方式。
② Filter配置:
<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.xml文件中增加了如上任意一种配置,程序就可以在Spring配置文件中使用request或session作用域了。
如果Web应用直接使用Spring MVC作为MVC框架,即用SpringDispatcherServlet或DispatcherPortlet来拦截用户请求,则无须这些额外的配置,因为SpringDispatcherServlet或DispatcherPortlet已经处理了所有和请求有关的状态处理。