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官方文檔等資料。

相關文章
相關標籤/搜索