如何选择合适的bean范围?


Answers:


485

介绍

它表示bean的范围(生存期)。如果您熟悉基本Servlet Web应用程序的“幕后”工作,这将更容易理解:Servlet如何工作?实例化,会话,共享变量和多线程


@Request/View/Flow/Session/ApplicationScoped

一个@RequestScopedbean的生命,只要一个HTTP请求响应周期(注意,Ajax请求算作一个HTTP请求太)。一个@ViewScopedbean的生命,只要你与通过调用操作方法返回回送相同的JSF视图交互null/ void无任何导航/重定向。一个@FlowScopedbean的生命,只要你通过的流量配置文件中注册的视图指定的集合导航。一个@SessionScopedbean的生命,只要建立HTTP会话。一@ApplicationScoped豆住,只要运行Web应用程序。请注意,CDI @Model基本上是一个刻板@Named @RequestScoped,所以规则也同样适用。

选择哪个范围仅取决于bean持有和表示的数据(状态)。使用@RequestScoped简单和非Ajax表格/演示。使用@ViewScoped了丰富的支持Ajax的动态视图(ajaxbased验证,渲染,对话框等)。使用@FlowScoped的“向导”(“问卷”)在多个页面收集的输入数据传播的模式。使用@SessionScoped客户端的具体数据,如登录的用户和用户偏好(语言等)。使用@ApplicationScoped应用程序范围内的数据/常量,比如下拉列表,是适合每一个人,或管理的bean没有任何实例变量和仅有的方法相同。

@ApplicationScopedbean用于会话/视图/请求范围的数据会使其在所有用户之间共享,因此其他任何人都可以看到彼此的数据,这完全是错误的。将@SessionScopedbean用于视图/请求范围的数据会使其在单个浏览器会话中的所有选项卡/窗口之间共享,因此最终用户在选项卡之间切换后与每个视图进行交互时可能会遇到麻烦,这不利于用户体验。将@RequestScopedbean用作视图作用域数据将使视图作用域数据在每次单次(ajax)回发时都被重新初始化为默认值,从而可能导致无法使用的表单(另请参见第4点和第5点)。滥用@ViewScopedbean来获取请求,会话或应用程序范围的数据,并滥用@SessionScoped 用于应用程序范围的数据的bean不会影响客户端,但是不必要地占用了服务器内存,并且效率很低。

请注意,除非您确实具有较低的内存占用空间并且希望完全无状态,否则不应根据性能的影响来选择范围。您将需要专门使用@RequestScopedbean和带有请求参数的小提琴来维持客户端的状态。还要注意,当您只有一个JSF页面具有不同范围的数据时,将它们放在与数据范围相匹配的范围内的单独的支持bean中是完全有效的。@ManagedProperty在JSF托管Bean或@InjectCDI托管Bean的情况下,Bean只能通过彼此访问。

也可以看看:


@CustomScoped/NoneScoped/Dependent

您的问题中没有提到,但(传统)JSF还支持@CustomScoped@NoneScoped,这在现实世界中很少使用。在@CustomScoped必须引用定制的Map<K, Bean>,其中有一些重载更大范围的实现Map#put()和/或Map#get()以有超过bean创建更为精细的控制和/或破坏。

JSF @NoneScoped和CDI@Dependent只要在bean上进行一次EL评估,基本上就可以存在。想象一下一个登录表单,其中有两个输入字段引用一个bean属性,一个命令按钮引用一个bean操作,因此总共有三个EL表达式,那么实际上将创建三个实例。一种设置了用户名,一种设置了密码,另一种调用了操作。通常,您只想在应与注入的bean一样长的bean上使用此作用域。因此,如果将@NoneScoped@Dependent注入到中@SessionScoped,则它将与@SessionScopedbean 一样长。

也可以看看:


闪光灯范围

最后,JSF还支持Flash作用域。它由一个与会话范围内的数据条目相关联的短期Cookie支持。重定向之前,将在HTTP响应上设置一个cookie,该cookie的值与会话范围内的数据条目唯一关联。重定向后,将检查Flash作用域cookie的存在,并将与cookie关联的数据条目从会话作用域中删除,并将其放入重定向请求的请求作用域中。最后,cookie将从HTTP响应中删除。这样,重定向的请求可以访问在初始请求中准备的请求范围的数据。

实际上,这不能作为托管bean范围使用,即不存在@FlashScoped。闪存作用域仅通过ExternalContext#getFlash()托管Bean和#{flash}EL中的地图可用。

也可以看看:


4
我认为对的问题“ 在JSF中如何以及何时破坏View作用域bean?的回答这里很重要。
Lii

3
@Cold:这是一个旧的CDI范围,在JSF 2.2中被替换为@FlowScoped(无需手动启动/停止它)。
BalusC

1
而DeltaSpike还具有ViewAccesscopedWindowScoped
Kukeltje

@BalusC,我认为ViewScopedMyFaces 2.2中的bean 存在问题。我目前在ViewScopedBean和Ajax上遇到了问题,这些问题已在此处发布。在MyFaces JIRA中,也对此主题进行了讨论
Tapas Bose

CDI定义了四个内置范围: @RequestScoped @SessionScoped @ApplicationScoped @ConversationScoped 为什么您描述的范围不同?
侯赛因·阿卡贾尼

122

从JSF 2.3 javax.faces.bean开始,已弃用package package中定义的所有bean作用域,以使作用域与CDI保持一致。此外,它们仅在您的bean使用@ManagedBean注释时才适用。如果您使用的JSF版本低于2.3,请参考最后的遗留答案。


从JSF 2.3开始,这里是可以在JSF Backing Bean上使用的范围:

1@javax.enterprise.context.ApplicationScoped .:应用程序范围在Web应用程序的整个持续时间内一直存在。该范围在所有请求和所有会话之间共享。当您拥有整个应用程序的数据时,这很有用。

2 .@javax.enterprise.context.SessionScoped:会话范围从建立会话到会话终止一直存在。会话上下文在同一HTTP会话中发生的所有请求之间共享。当您不想为特定会话保存特定客户端的数据时,此功能很有用。

3 .@javax.enterprise.context.ConversationScoped:对话范围随着bean的存在而保持为日志。范围提供2种方法:Conversation.begin()Conversation.end()。这些方法应显式调用,以开始或结束Bean的生命。

4.:@javax.enterprise.context.RequestScoped请求范围是短暂的。它在提交HTTP请求时开始,在将响应发送回客户端后结束。如果将托管bean放入请求范围,则会为每个请求创建一个新实例。如果您担心会话范围存储的成本,则值得考虑请求范围。

5@javax.faces.flow.FlowScoped .:只要Flow存在,Flow范围就会持续存在。流可以定义为一组包含页面(或视图)的页面,这些页面定义了一个工作单元。只要用户在Flow中进行导航,作用域就可以激活。

6@javax.faces.view.ViewScoped .:重新显示相同的JSF页面时,视图范围内的bean仍然存在。一旦用户导航到另一个页面,Bean就会超出范围。


以下遗留答案适用于2.3之前的JSF版本

从JSF 2.x开始,有4个Bean范围:

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

会议范围: 会话范围从建立会话的时间一直持续到会话终止。如果Web应用程序在HttpSession对象上调用invalidate方法,或者会话超时,则会话终止。

RequestScope: 请求范围是短暂的。它在提交HTTP请求时开始,在将响应发送回客户端后结束。如果将托管bean放入请求范围,则会为每个请求创建一个新实例。如果您担心会话范围存储的成本,则值得考虑请求范围。

适用范围: 应用程序作用域在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] 在此处输入图片说明


您能否澄清一下,“ HttpSession对象上的invalidate方法”是什么意思:invalidate()方法还是无效方法?
亚历山大·波兹涅夫

1
可能有点老了,也许迟到了,但要澄清一下:FacesContext.getCurrentInstance().getExternalContext().invalidateSession();他的意思是在“注销bean”中被调用。
罗兰

1
它成为了传统答案,目前有8个作用域
Ewoks

@KishorPrakash:现在已经有6个月了。;-)
库克尔杰(Kukeltje)

@Kukeltje:抱歉,我在上面。
基什·普拉卡什
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.