如何选择合适的bean作用域? [英] How to choose the right bean scope?

查看:24
本文介绍了如何选择合适的bean作用域?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到有不同的 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 应用程序的工作:servlet 是如何工作的?实例化、会话、共享变量和多线程.

A @RequestScoped bean 的生命周期与单个 HTTP 请求-响应周期一样长(请注意,Ajax 请求也算作单个 HTTP 请求).@ViewScoped 只要您通过回发与相同的 JSF 视图交互,bean 就一直存在,回发调用返回 null/void 的操作方法,而无需任何导航/重定向.@FlowScoped 只要您在流配置文件中注册的指定视图集合中导航,bean 就会一直存在.@SessionScoped bean 的生命周期与建立的 HTTP 会话一样长.@ApplicationScoped 只要 Web 应用程序运行,bean 就会一直存在.请注意,CDI @Model 基本上是一个 stereotype,因此适用相同的规则.

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)回发时重新初始化为默认值,从而导致可能无法工作的表单(另请参见此处的第 4 点和第 5 点).为请求、会话或应用程序范围的数据滥用 @ViewScoped bean,为应用程序范围的数据滥用 @SessionScoped bean 不会影响客户端,但它会不必要地占用服务器内存,效率低下.

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.

您的问题中没有提到,但(旧版)JSF 也支持 @CustomScoped@NoneScoped,在现实世界中很少使用.@CustomScoped 必须在更广泛的范围内引用自定义的 Map 实现,该实现覆盖了 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 应该与注入它的 bean 一样长.因此,如果 @NoneScoped@Dependent 被注入到 @SessionScoped 中,那么它将与 @SessionScoped 豆.

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.

最后,JSF 还支持 flash 作用域.它由与会话范围内的数据条目相关联的短期 cookie 支持.在重定向之前,将在 HTTP 响应上设置一个 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.

这篇关于如何选择合适的bean作用域?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆