如何选择合适的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}做为映射使用。

也能够看看:

相关文章
相关标签/搜索