如何选择合适的bean范围? [英] How to choose the right bean scope?
问题描述
我注意到有不同的bean作用域,例如:
I noticed that there are different bean scopes like:
@RequestScoped
@ViewScoped
@FlowScoped
@SessionScoped
@ApplicationScoped
每个的目的是什么?如何为我的bean选择合适的范围?
What is the purpose of each? How do I choose a proper scope for my bean?
推荐答案
简介
它表示bean的作用域(生存期).如果您熟悉基本servlet Web应用程序的幕后"工作,这将更容易理解: @RequestScoped
bean生存只要一个HTTP请求-响应周期(请注意,Ajax请求也算作一个HTTP请求). @ViewScoped
bean的生存时间只要您正在通过回发与同一JSF视图进行交互,该回发调用了返回null
/void
的操作方法,而没有任何导航/重定向. @FlowScoped
bean的生存时间只要您正在浏览流配置文件中注册的指定视图集合.一个 @SessionScoped
bean的生存时间只要建立的HTTP会话. @ApplicationScoped
bean的生存时间只要Web应用程序运行.请注意,CDI @Model
本质上是定型@Named @RequestScoped
的a>,因此适用相同的规则.
A @RequestScoped
bean lives as long as a single HTTP request-response cycle (note that an Ajax request counts as a single HTTP request too). A @ViewScoped
bean lives as long as you're interacting with the same JSF view by postbacks which call action methods returning null
/void
without any navigation/redirect. A @FlowScoped
bean lives as long as you're navigating through the specified collection of views registered in the flow configuration file. A @SessionScoped
bean lives as long as the established HTTP session. An @ApplicationScoped
bean lives as long as the web application runs. Note that the CDI @Model
is basically a stereotype for @Named @RequestScoped
, so same rules apply.
选择哪个范围仅取决于bean所保存和表示的数据(状态).将@RequestScoped
用于简单和非ajax表单/表示.将@ViewScoped
用于启用了富Ajax的动态视图(基于ajax的验证,渲染,对话框等).将@FlowScoped
用于收集分布在多个页面上的输入数据的向导"(问卷")模式.将@SessionScoped
用于客户端特定的数据,例如登录的用户和用户首选项(语言等).将@ApplicationScoped
用于应用程序范围的数据/常量,例如对于每个人都相同的下拉列表,或没有任何实例变量且仅具有方法的托管bean.
Which scope to choose depends solely on the data (the state) the bean holds and represents. Use @RequestScoped
for simple and non-ajax forms/presentations. Use @ViewScoped
for rich ajax-enabled dynamic views (ajaxbased validation, rendering, dialogs, etc). Use @FlowScoped
for the "wizard" ("questionnaire") pattern of collecting input data spread over multiple pages. Use @SessionScoped
for client specific data, such as the logged-in user and user preferences (language, etc). Use @ApplicationScoped
for application wide data/constants, such as dropdown lists which are the same for everyone, or managed beans without any instance variables and having only methods.
滥用@ApplicationScoped
bean来获取会话/视图/请求范围的数据将使其在所有用户之间共享,因此其他任何人都可以看到彼此的数据,这完全是错误的.将@SessionScoped
bean用于视图/请求范围的数据将使其在单个浏览器会话中的所有选项卡/窗口之间共享,因此最终用户在选项卡之间切换后与每个视图进行交互时可能会遇到麻烦,这不利于用户体验.将@RequestScoped
bean用作视图作用域数据将使视图作用域数据在每个单个(ajax)回发中都重新初始化为默认值,从而可能导致无法使用的表单(
Abusing an @ApplicationScoped
bean for session/view/request scoped data would make it to be shared among all users, so anyone else can see each other's data which is just plain wrong. Abusing a @SessionScoped
bean for view/request scoped data would make it to be shared among all tabs/windows in a single browser session, so the enduser may experience inconsitenties when interacting with every view after switching between tabs which is bad for user experience. Abusing a @RequestScoped
bean for view scoped data would make view scoped data to be reinitialized to default on every single (ajax) postback, causing possibly non-working forms (see also points 4 and 5 here). Abusing a @ViewScoped
bean for request, session or application scoped data, and abusing a @SessionScoped
bean for application scoped data doesn't affect the client, but it unnecessarily occupies server memory and is plain inefficient.
请注意,除非您确实具有较低的内存占用空间并且希望完全变为无状态,否则不应根据性能的影响来选择范围.您只需要使用@RequestScoped
bean并使用请求参数来保持客户端的状态.还要注意,当您只有一个JSF页面具有不同范围的数据时,将它们放在与数据范围相匹配的范围中的单独的支持bean中是完全有效的.如果是JSF管理的bean,则这些bean可以通过@ManagedProperty
彼此访问;如果是使用CDI的bean,则可以通过@Inject
彼此访问.
Note that the scope should rather not be chosen based on performance implications, unless you really have a low memory footprint and want to go completely stateless; you'd need to use exclusively @RequestScoped
beans and fiddle with request parameters to maintain the client's state. Also note that when you have a single JSF page with differently scoped data, then it's perfectly valid to put them in separate backing beans in a scope matching the data's scope. The beans can just access each other via @ManagedProperty
in case of JSF managed beans or @Inject
in case of CDI managed beans.
- Difference between View and Request scope in managed beans
- Advantages of using JSF Faces Flow instead of the normal navigation system
- Communication in JSF2 - Managed bean scopes
您的问题中未提及,但是(传统)JSF还支持 @CustomScoped
和 @NoneScoped
,在现实世界中很少使用. @CustomScoped
必须在更广泛的范围内引用自定义的Map<K, Bean>
实现,该实现已覆盖了Map#put()
和/或Map#get()
,以便对Bean创建和/或销毁有更精细的控制.
It's not mentioned in your question, but (legacy) JSF also supports @CustomScoped
and @NoneScoped
, which are rarely used in real world. The @CustomScoped
must refer a custom Map<K, Bean>
implementation in some broader scope which has overridden Map#put()
and/or Map#get()
in order to have more fine grained control over bean creation and/or destroy.
JSF @NoneScoped
和CDI @Dependent
基本上只要在bean上进行一次EL评估就可以使用.想象一下一个登录表单,其中有两个输入字段引用一个bean属性,一个命令按钮引用一个bean操作,因此总共有三个EL表达式,那么实际上将创建三个实例.一种设置了用户名,一种设置了密码,另一种调用了操作.通常,您只想在应与注入的bean一样长的bean上使用此作用域.因此,如果将@NoneScoped
或@Dependent
注入到@SessionScoped
中,则它将与@SessionScoped
bean一样长寿.
The JSF @NoneScoped
and CDI @Dependent
basically lives as long as a single EL-evaluation on the bean. Imagine a login form with two input fields referring a bean property and a command button referring a bean action, thus with in total three EL expressions, then effectively three instances will be created. One with the username set, one with the password set and one on which the action is invoked. You normally want to use this scope only on beans which should live as long as the bean where it's being injected. So if a @NoneScoped
or @Dependent
is injected in a @SessionScoped
, then it will live as long as the @SessionScoped
bean.
- Expire specific managed bean instance after time interval
- what is none scope bean and when to use it?
- What is the default Managed Bean Scope in a JSF 2 application?
最后,JSF还支持Flash作用域.它由一个与会话范围内的数据条目相关联的短期Cookie支持.重定向之前,将在HTTP响应上设置一个cookie,该cookie的值与会话范围内的数据条目唯一关联.重定向之后,将检查Flash作用域cookie的存在,并将与cookie关联的数据条目从会话作用域中删除,并将其放入重定向请求的请求作用域中.最后,该cookie将被从HTTP响应中删除.通过这种方式,重定向的请求可以访问在初始请求中准备的请求范围的数据.
As last, JSF also supports the flash scope. It is backed by a short living cookie which is associated with a data entry in the session scope. Before the redirect, a cookie will be set on the HTTP response with a value which is uniquely associated with the data entry in the session scope. After the redirect, the presence of the flash scope cookie will be checked and the data entry associated with the cookie will be removed from the session scope and be put in the request scope of the redirected request. Finally the cookie will be removed from the HTTP response. This way the redirected request has access to request scoped data which was been prepared in the initial request.
这实际上不能用作托管bean范围,即不存在@FlashScoped
之类的东西. Flash范围只能通过 ExternalContext#getFlash()
在托管bean中,在#{flash}
在EL中.
This is actually not available as a managed bean scope, i.e. there's no such thing as @FlashScoped
. The flash scope is only available as a map via ExternalContext#getFlash()
in managed beans and #{flash}
in EL.
- How to show faces message in the redirected page
- Pass an object between @ViewScoped beans without using GET params
- CDI missing @ViewScoped and @FlashScoped
这篇关于如何选择合适的bean范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!