我注意到有不同的bean作用域,例如:
@RequestScoped
@ViewScoped
@FlowScoped
@SessionScoped
@ApplicationScoped
每个的目的是什么? 如何为我的bean选择合适的范围?
#1楼
从JSF 2.3开始,已弃用javax.faces.bean包中定义的所有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 :视图范围内的Bean在重新显示同一JSF页面时仍然存在。 一旦用户导航到另一个页面,Bean就会超出范围。
以下遗留答案适用于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}作为映射使用。
也可以看看:
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3166873