Spring容器中Bean的做用域

    当经过Spring容器建立一个Bean实例时,不只能够完成Bean实例的实例化,还能够为Bean指定特定的做用域。Spring支持以下5种做用域: java

  • singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例web

  • prototype:原型模式,每次经过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例spring

  • request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不一样的Bean实例。只有在Web应用中使用Spring时,该做用域才有效session

  • session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。一样只有在Web应用中使用Spring时,该做用域才有效app

  • globalsession:每一个全局的HTTP Session,使用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做用域。 url

  设置Bean的基本行为,经过scope属性指定,该属性能够接受singleton、prototype、request、session、globlesession5个值,分别表明以上5种做用域。下面的配置片断中,singleton和prototype各有一个: spa

<!-- 默认的做用域:singleton -->
<bean id="p1" class="com.abc.Person" /> 
<!-- 指定的做用域:prototype -->
<bean id="p2" class="com.abc.Person" scope="prototype" />

  下面是一个测试类: prototype

public class BeanTest {
  public static void main(String args[]) {
    //加载类路径下的beans.xml文件以初始化Spring容器
    ApplicationContext context = new ClassPathXmlApplicationContext();
    //分两次分别取同一个Bean,比较两者是不是同一个对象
    System.out.println(context.getBean("p1") == context.getBean("p1"));
    System.out.println(context.getBean("p2") == context.getBean("p2"));
  }
}

  执行结果分别是:true和false

  从结果能够看出,正如上文所述:对于singleton做用域的Bean,每次请求该id的Bean,都将返回同一个实例,而prototype做用域的Bean, 每次请求都将产生全新的实例。

  注意:早期指定Bean的做用域也可经过singleton属性指定,该属性只接受两个属性值:true和false,分别表明singleton和prototype的做用域。使用singleton属性则没法指定其余三个做用域。实际上Spring2.X不推荐使用singleton属性指定Bean的做用域,singleton属性是Spring 1.2.X的使用方式。

  对于request做用域,查看以下Bean定义:

<bean id="loginAction" class="com.abc.LoginAction" scope="request" />

  针对每次HTTP请求,Spring容器会根据loginActionBean定义建立一个全新的LoginAction实例,且该loginAction实例尽在当前HTTP Request内有效。所以,若是程序须要,彻底能够自由更改Bean实例的内部状态;其余请求所得到的loginAction实例没法感受到这种内部状态的改变。当处理请求结束时,request做用域的Bean将会被销毁。

  注意:request、session做用域的Bean只对Web应用才真正有效。实际上一般只会将Web应用的控制器Bean才指定成request做用域

  session做用域与request做用域彻底相似,区别在于:request做用域的Bean对于每次HTTP请求有效,而session做用域的Bean对于每次Session有效。在Web应用中,为了让request和session做用域生效,必须将HTTP请求对象绑定到为该请求提供服务的线程上,这使得具备request和session做用域的Bean实例可以在后面的调用链中被访问到。

  为此咱们有两种配置方式:采用Listener配置或者采用Filter配置。当使用Servlet 2.4及以上规范的Web容器时,咱们能够在Web应用的web.xml文件中增长Listener配置,该Listener负责为request做用域生效:

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

  若是使用了只支持Servlet 2.4之前规范的Web容器,则该容器不支持Listener规范,故没法使用这种配置方式,只能改成使用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做用域了。下面是Spring配置文件的片断:

<bean id="p3" class="com.abc.Person" scope="request" />

  这样,Spring容器会每次HTTP请求都生成一个Person实例,当该请求响应结束时,该实例也随之消失。

  若是Web应用直接使用Spring MVC做为MVC框架,即便用SpringDispatcherServlet或DispatcherPortlet来链接全部用户请求,则无需这些额外的配置,由于他们已经处理了全部和请求有关的状态处理。

  注意:Spring 3.0 不只能够为Bean指定已经存在的5个做用域,还支持自定义做用域,关于自定义做用域的内容,请参看Spring官方文档等资料。

相关文章
相关标签/搜索