我注意到有不同的Bean作用域,如:
@RequestScoped
@ViewScoped
@FlowScoped
@SessionScoped
@ApplicationScoped
每个作用域的目的是什么?我该如何选择合适的作用域来定义我的 bean?
我注意到有不同的Bean作用域,如:
@RequestScoped
@ViewScoped
@FlowScoped
@SessionScoped
@ApplicationScoped
每个作用域的目的是什么?我该如何选择合适的作用域来定义我的 bean?
它代表了bean的范围(生命周期)。如果您熟悉基本servlet Web应用程序的“底层”工作方式,则更容易理解:Servlet如何工作?实例化、会话、共享变量和多线程。
@Request/View/Flow/Session/ApplicationScoped
一个@RequestScoped
bean的生命周期与单个HTTP请求-响应周期相同(注意,Ajax请求也算作单个HTTP请求)。一个@ViewScoped
bean的生命周期与您通过调用返回null
/void
且没有导航/重定向的操作方法与JSF视图进行交互的时间相同。一个@FlowScoped
bean的生命周期与您在流配置文件中注册的指定视图集合中导航的时间相同。一个@SessionScoped
bean的生命周期与已建立的HTTP会话一样长。一个@ApplicationScoped
bean的生命周期与Web应用程序运行的时间相同。请注意,CDI @Model
基本上是@Named @RequestScoped
的stereotype,因此适用相同的规则。
@RequestScoped
。对于富含ajax的动态视图(基于ajax的验证、渲染、对话框等),请使用@ViewScoped
。对于收集分布在多个页面上的输入数据的“向导”(“问卷”)模式,请使用@FlowScoped
。对于客户端特定数据,例如已登录用户和用户首选项(语言等),请使用@SessionScoped
。对于应用程序范围的数据/常量,例如下拉列表是每个人都相同的,或者只有方法而没有实例变量的托管bean,请使用@ApplicationScoped
。@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上使用此范围。因此,如果在@SessionScoped
中注入@NoneScoped
或@Dependent
,则它将与@SessionScoped
bean一样长寿。
最后,JSF 还支持 Flash 作用域。它由一个与会话作用域中的数据条目关联的寿命短暂的 cookie 支持。在重定向之前,将在 HTTP 响应上设置一个 cookie,该 cookie 的值与会话作用域中的数据条目唯一关联。重定向后,将检查 Flash 作用域 cookie 的存在,并将与 cookie 关联的数据条目从会话作用域中删除并放入重定向请求的请求作用域中。最后,将从 HTTP 响应中删除 cookie。这样,重定向请求就可以访问在初始请求中准备好的请求作用域数据。
实际上,Flash 作用域不能作为托管 Bean 作用域使用,即没有像 @FlashScoped
这样的东西。通过 ExternalContext#getFlash()
在托管 Bean 中仅可将 Flash 作用域作为映射访问,而在 EL 中使用 #{flash}
。
自从JSF 2.3版本以后,javax.faces.bean
包中定义的所有bean作用域都已被弃用,以使作用域与CDI对齐。此外,它们仅适用于使用@ManagedBean
注释的bean。如果您使用的是低于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
: 流程范围持续时间与流程一样长。流程可以定义为一组包含的页面(或视图),用于定义工作单元。只要用户在流程中导航,流程范围的bean就处于活动状态。
6. @javax.faces.view.ViewScoped
: 视图范围内的bean在重新显示相同的JSF页面时持久存在。一旦用户导航到不同的页面,bean就会失去作用范围。
来源:Core Java Server Faces第3版,David Geary和Cay Horstmann著[第51-54页]
(注:此处为格式要求,无需翻译)invalidate()
方法还是无效方法? - Alexander PozdneevFacesContext.getCurrentInstance().getExternalContext().invalidateSession();
。 - Roland
@FlowScoped
替代(无需手动启动/停止)。 - BalusCViewAccesscoped
和WindowScoped
。 - KukeltjeViewScoped
bean有关。我目前正在面临一个ViewScoped
bean和Ajax的问题,我已经在这里发布了。在MyFaces JIRA中,也有一个讨论关于这个主题。 - Tapas Bose`@RequestScoped` `@SessionScoped` `@ApplicationScoped` `@ConversationScoped`
为什么你所描述的这些作用域是不同的呢? - Hosein Aqajani