如何选择正确的bean范围?

我注意到有不同的bean范围,比如:

@RequestScoped
@ViewScoped
@FlowScoped
@SessionScoped
@ApplicationScoped

每一个的目的是什么?我如何为我的bean选择合适的范围?

230922 次浏览

简介

它表示bean的范围(生命周期)。如果你熟悉“under the coveres "under the coveres "一个基本的servlet web应用程序:servlet是如何工作的?实例化、会话、共享变量和多线程


@Request/View/Flow/Session/ApplicationScoped

@RequestScoped bean存在的时间与单个HTTP请求-响应周期一样长(注意Ajax请求也算作单个HTTP请求)。只要你通过回发与相同的JSF视图交互,@ViewScoped0 bean就会存在,这些回发调用操作方法返回null/void,而不需要任何导航/重定向。只要你在流配置文件中注册的指定视图集合中导航,@ViewScoped1 bean就会存在。@ViewScoped2 bean与建立的HTTP会话一样存在。只要web应用程序运行,@ViewScoped3 bean就存在。注意,CDI @Model基本上是@Named @RequestScoped@ViewScoped4,所以同样的规则适用。

选择哪个作用域完全取决于bean持有和表示的数据(状态)。对于简单和非ajax表单/表示,使用@RequestScoped。使用@ViewScoped来获得丰富的ajax动态视图(基于ajax的验证、渲染、对话框等)。使用@FlowScoped作为“wizard”;(“问卷调查”)模式收集的输入数据分布在多个页面。对客户端特定的数据使用@SessionScoped,例如登录用户和用户首选项(语言等)。对应用程序范围内的数据/常量使用@ApplicationScoped,例如对每个人都相同的下拉列表,或者没有任何实例变量而只有方法的托管bean。

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

注意,范围的选择不应该基于性能影响,除非你真的有一个低内存占用并且想要完全无状态;你需要专门使用@RequestScoped bean并修改请求参数来维护客户端状态。还要注意,当您有一个具有不同作用域数据的JSF页面时,将它们放在与数据作用域匹配的作用域中的独立支持bean中是完全有效的。这些bean只能通过@ManagedProperty(对于JSF托管bean)或@Inject(对于CDI托管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应该与注入它的bean一样存在。因此,如果@NoneScoped@Dependent被注入到@SessionScoped bean中,那么它将和@SessionScoped bean一样存在。

参见:


Flash范围

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

这实际上不能作为托管bean作用域使用,即没有@FlashScoped这样的东西。flash作用域只能通过托管bean中的ExternalContext#getFlash()和EL中的#{flash}作为映射来使用。

参见:

自JSF 2.3以来,所有在包javax.faces.bean包中定义的bean作用域都已弃用,以便将作用域与CDI对齐。此外,它们只适用于bean使用@ManagedBean注释的情况。如果您使用的是2.3以下的JSF版本,请参考最后的遗留答案。


从JSF 2.3开始,这里有一些可以在JSF Backing Beans上使用的作用域:

1. @javax.enterprise.context.ApplicationScoped:应用程序作用域在web应用程序的整个运行期间持续存在。该范围在所有请求和所有会话之间共享。当您拥有整个应用程序的数据时,这非常有用。

2. @javax.enterprise.context.SessionScoped:会话范围从会话建立开始一直持续到会话终止。会话上下文在同一个HTTP会话中发生的所有请求之间共享。当您不习惯为特定客户端保存特定会话的数据时,这非常有用。

3.@javax.enterprise.context.ConversationScoped:会话作用域在bean存在时一直存在。作用域提供了两个方法:Conversation.begin()Conversation.end()。应该显式地调用这些方法,以开始或结束bean的生命周期。

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

5. @javax.faces.flow.FlowScoped:只要流存在,流作用域就会持续存在。流可以定义为定义工作单元的包含页面(或视图)集。只要用户在流中导航,流范围是活动的。

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


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

从JSF 2开始。x有4个Bean scope:

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

会话范围:会话范围从会话建立开始一直持续到会话终止。会话结束 上的invalidate方法

. HttpSession对象

RequestScope:请求范围是短时间的。它在提交HTTP请求时开始,在发送回响应后结束 到客户端。如果您将托管bean放入请求范围,则会出现一个新的 实例与每个请求一起创建。这个请求值得考虑

.

.

.

ApplicationScope:应用程序作用域在web应用程序的整个持续时间内持续存在。这个范围是所有人共享的 请求和所有会话。您将管理bean放入 应用程序范围(如果一个bean应该在所有bean之间共享) web应用程序的实例。bean是在它存在时构造的 首先由应用程序的任何用户请求,并且它保持活动状态 直到web应用程序从应用服务器上删除

ViewScope:视图作用域在JSF 2.0中添加。当相同的JSF页面重新显示时,视图范围内的bean将继续存在。(JSF 规范使用术语视图来描述JSF页面。)只要用户 导航到另一个页面,bean超出作用域

根据您的需求选择范围。

来源: 核心Java服务器面向第三版 by David Geary &Cay Horstmann[第1页]51 - 54] enter image description here