如何選擇合適的bean範圍?

我注意到有不一樣的bean做用域,例如: html

@RequestScoped
@ViewScoped
@FlowScoped
@SessionScoped
@ApplicationScoped

每一個的目的是什麼? 如何爲個人bean選擇合適的範圍? java


#1樓

從JSF 2.3開始,已棄用javax.faces.bean包中定義的全部bean做用域,以使做用域與CDI對齊。 此外,它們僅在您的bean使用@ManagedBean註釋時才適用。 若是您使用的JSF版本低於2.3,請參考最後的遺留答案。 ajax


從JSF 2.3開始,這裏是能夠在JSF Backing Bean上使用的範圍: api

1. @javax.enterprise.context.ApplicationScoped :應用程序做用域在Web應用程序的整個持續時間內一直存在。 該範圍在全部請求和全部會話之間共享。 當您擁有整個應用程序的數據時,這頗有用。 瀏覽器

2. @javax.enterprise.context.SessionScoped :會話範圍從創建會話的時間一直持續到會話終止爲止。 會話上下文在同一HTTP會話中發生的全部請求之間共享。 當您不想爲特定會話保存特定客戶端的數據時,此功能頗有用。 服務器

3. @javax.enterprise.context.ConversationScoped :對話範圍隨着bean的存在而保持爲日誌。 範圍提供2種方法: Conversation.begin()Conversation.end() 。 這些方法應顯式調用,以開始或結束Bean的生命。 cookie

4. @javax.enterprise.context.RequestScoped :請求範圍是短暫的。 它在提交HTTP請求時開始,在將響應發送回客戶端後結束。 若是將託管bean放入請求範圍,則會爲每一個請求建立一個新實例。 若是您擔憂會話範圍存儲的成本,則值得考慮請求範圍。 多線程

5. @javax.faces.flow.FlowScoped :只要Flow存在,Flow範圍就會持續存在。 流能夠定義爲一組包含頁面(或視圖)的頁面,這些頁面定義了一個工做單元。 只要用戶在Flow中進行導航,做用域就能夠激活。 oracle

6. @javax.faces.view.ViewScoped :視圖範圍內的Bean在從新顯示同一JSF頁面時仍然存在。 一旦用戶導航到另外一個頁面,Bean就會超出範圍。 app


如下遺留答案適用於2.3以前的JSF版本

從JSF 2.x開始,有4個Bean範圍:

  • @SessionScoped
  • @RequestScoped
  • @ApplicationScoped
  • @ViewScoped

會話範圍:會話範圍從創建會話到會話終止一直存在。 若是Web應用程序在HttpSession對象上調用invalidate方法,或者會話超時,則會話終止。

RequestScope:請求範圍是短暫的。 它在提交HTTP請求時開始,在將響應發送回客戶端後結束。 若是將託管bean放入請求範圍,則會爲每一個請求建立一個新實例。 若是您擔憂會話範圍存儲的成本,則值得考慮請求範圍。

ApplicationScope:應用程序做用域在Web應用程序的整個過程當中一直存在。 該範圍在全部請求和全部會話之間共享。 若是應在Web應用程序的全部實例之間共享單個bean,則將託管bean放入應用程序範圍。 Bean是在應用程序的任何用戶首次請求時構造的,而且一直保持活動狀態,直到從應用程序服務器中刪除Web應用程序爲止。

ViewScope: View範圍是在JSF 2.0中添加的。 從新顯示相同的JSF頁面時,視圖範圍內的bean仍然存在。 (JSF規範將術語「視圖」用於JSF頁面。)一旦用戶導航到另外一個頁面,Bean就會超出範圍。

根據須要選擇範圍。

資料來源: David Geary和Cay Horstmann撰寫的Core Java Server Faces第三版 [頁面編號。 51-54] 在此處輸入圖片說明


#2樓

介紹

它表明了bean的範圍(生存期)。 若是您熟悉基本Servlet Web應用程序的「幕後」工做,這將更容易理解: Servlet如何工做? 實例化,會話,共享變量和多線程


@Request/View/Flow/Session/ApplicationScoped

@RequestScoped bean的生存時間與單個HTTP請求-響應週期同樣長(請注意,Ajax請求也計爲單個HTTP請求)。 只要您經過回發與同一JSF視圖進行交互, @ViewScoped bean就會存在,該回發調用操做方法返回null / void而不進行任何導航/重定向。 只要您在流配置文件中註冊的指定視圖集合中導航, @FlowScoped bean就會存在。 @SessionScoped bean與已創建的HTTP會話同樣長。 一個@ApplicationScoped豆的生活,只要運行Web應用程序。 請注意,CDI @Model基本上是一個刻板@Named @RequestScoped ,因此規則也一樣適用。

選擇哪一個範圍僅取決於bean持有和表示的數據(狀態)。 將@RequestScoped用於簡單和非ajax表單/表示。 將@ViewScoped用於啓用豐富的Ajax的動態視圖(基於ajax的驗證,渲染,對話框等)。 將@FlowScoped用於收集多個頁面上的輸入數據的「嚮導」(「問卷」)模式。 將@SessionScoped用於客戶端特定的數據,例如登陸的用戶和用戶首選項(語言等)。 將@ApplicationScoped用於整個應用程序範圍的數據/常量,例如對於每一個人都相同的下拉列表,或沒有任何實例變量且僅具備方法的託管bean。

@ApplicationScoped bean用做會話/視圖/請求範圍的數據將使其在全部用戶之間共享,所以其餘任何人均可以看到彼此的數據,這徹底是錯誤的。 將@SessionScoped bean用於視圖/請求範圍的數據將使其在單個瀏覽器會話中的全部選項卡/窗口之間共享,所以最終用戶在選項卡之間切換後與每一個視圖進行交互時可能會遇到麻煩,這不利於用戶體驗。 將@RequestScoped bean用做視圖做用域數據將使視圖做用域數據在每次單個(ajax)回發時都從新初始化爲默認值,從而可能致使沒法正常工做的表單( 另請參見此處的第4點和第5點 )。 將@ViewScoped bean用做請求,會話或應用程序範圍的數據,並將@SessionScoped bean用做應用程序範圍的數據不會影響客戶端,但會沒必要要地佔用服務器內存,而且效率很低。

請注意,除非您確實具備較低的內存佔用空間而且但願徹底無狀態,不然不該根據性能的影響來選擇範圍。 您只須要使用@RequestScoped bean並使用請求參數來維護客戶端的狀態。 還要注意,當您只有一個JSF頁面具備不一樣範圍的數據時,將它們放在與數據範圍相匹配的範圍中的單獨的支持bean中是徹底有效的。 若是是JSF管理的bean,則這些bean只能經過@ManagedProperty相互訪問;若是是CDI管理的bean,則能夠經過@Inject相互訪問。

也能夠看看:


@CustomScoped/NoneScoped/Dependent

您的問題中沒有提到,但(傳統)JSF還支持@CustomScoped@NoneScoped ,這在現實世界中不多使用。 @CustomScoped必須在更普遍的範圍內引用自定義Map<K, Bean>實現,該實現已覆蓋Map#put()和/或Map#get() ,以便對Bean建立和/或銷燬進行更精細的控制。

只要在bean上進行一次EL評估,JSF @NoneScoped和CDI @Dependent基本上就能夠存在。 想象一下一個登陸表單,其中有兩個輸入字段引用一個bean屬性,一個命令按鈕引用一個bean操做,所以總共有三個EL表達式,那麼實際上將建立三個實例。 一種設置了用戶名,一種設置了密碼,另外一種調用了操做。 一般,您只想在應與注入的bean同樣長的bean上使用此做用域。 所以,若是將@NoneScoped@Dependent注入@SessionScoped ,則它將與@SessionScoped bean同樣有效。

也能夠看看:


閃光燈範圍

最後,JSF還支持Flash做用域。 它由一個與會話範圍內的數據條目相關聯的短時間Cookie支持。 重定向以前,將在HTTP響應上設置一個cookie,該cookie的值與會話範圍內的數據條目惟一關聯。 重定向以後,將檢查Flash做用域cookie的存在,並將與cookie關聯的數據條目從會話做用域中刪除,並將其放入重定向請求的請求做用域中。 最後,cookie將從HTTP響應中刪除。 這樣,重定向的請求能夠訪問在初始請求中準備的請求範圍的數據。

實際上,這不能做爲託管bean範圍使用,即沒有@FlashScoped之類的東西。 Flash範圍僅可經過託管Bean中的ExternalContext#getFlash()和EL中的#{flash}做爲映射使用。

也能夠看看:

相關文章
相關標籤/搜索