如何select合适的bean范围?

我注意到有不同的bean作用域:

@RequestScoped @ViewScoped @FlowScoped @SessionScoped @ApplicationScoped 

每个的目的是什么? 我如何为我的豆select适当的范围?

介绍

它代表了bean的范围(生命周期)。 如果您熟悉基本servlet Web应用程序的“底层”,那么这更容易理解: servlet如何工作? 实例化,会话,共享variables和multithreading 。


@Request/View/Flow/Session/ApplicationScoped

一个@RequestScoped bean的存在时间与单个HTTP请求 – 响应周期一样长(请注意,Ajax请求也被视为一个HTTP请求)。 一个@ViewScoped bean只要通过@ViewScoped与同一个JSF视图进行交互,这些@ViewScoped调用操作方法返回null / void而不需要任何导航/redirect。 只要您浏览在streamconfiguration文件中注册的指定的视图集合, @FlowScoped bean就会一直存在。 @SessionScoped bean与build立的HTTP会话一样长。 只要Web应用程序运行,@ApplicationScoped bean就会@ApplicationScoped 。 请注意,CDI @Model基本上是@Named @RequestScoped ,所以应用了相同的规则。

select哪个范围取决于bean所持有和表示的数据(状态)。 使用@RequestScoped进行简单和非Ajax表单/演示。 使用@ViewScoped来实现丰富的支持Ajax的dynamic视图(基于AJAX的validation,渲染,对话框等)。 使用@FlowScoped作为收集跨越多个页面的input数据的“向导”(“问卷”)模式。 使用@SessionScoped来获取客户特定的数据,例如login用户和用户首选项(语言等)。 使用@ApplicationScoped作为应用程序范围的数据/常量,比如每个人都使用的下拉列表,或者没有任何实例variables并且只有方法的托pipebean。

为session / view / request范围的数据滥用@ApplicationScoped bean会使其在所有用户之间共享,所以任何人都可以看到彼此的数据,这是错误的。 滥用@SessionScoped bean来查看/请求作用域的数据会使得它在单个浏览器会话中的所有标签页/窗口之间共享,所以当在切换标签之间切换之后,最终用户在与每个视图交互时可能遇到不方便的情况,这对用户体验不利。 滥用@RequestScoped bean查看范围的数据会使视图范围的数据重新初始化为默认的每一个(Ajax)回发,导致可能的非工作forms( 这里也见点4和5 )。 为请求,会话或应用程序作用域数据滥用@ViewScoped bean,滥用@SessionScoped bean作为应用程序作用域的数据不会影响客户端,但它不必要地占用了服务器内存,而且效率低下。

请注意,范围不应根据性能影响进行select,除非您确实具有较低的内存占用量并且想要完全无状态; 你需要专门使用@RequestScoped bean,并且使用请求参数来维护客户端的状态。 还要注意,当你有一个JSF页面的数据范围不同时,把它们放在一个与数据范围匹配的范围内的单独的支持bean是完全有效的。 在JSF托pipe的bean的情况下,bean可以通过@ManagedProperty访问对方,或者在CDI托pipe的bean的情况下,可以通过@Inject

也可以看看:

  • 托pipebean中查看和请求范围之间的区别
  • 使用JSF Faces Flow代替普通导航系统的优势
  • JSF2中的通信 – 托pipe的bean作用域

@CustomScoped/NoneScoped/Dependent

在你的问题中没有提到,但(遗留的)JSF也支持@CustomScoped@NoneScoped ,这在现实世界中很less使用。 @CustomScoped必须在覆盖Map#put()和/或Map#get()更广泛的范围内引用一个自定义的Map<K, Bean>实现,以便对Bean创build和/或销毁有更好的细粒度控制。

JSF @NoneScoped和CDI @Dependent基本上只要对bean进行一次EL评估。 设想一个带有两个input字段的login表单,引用一个bean属性和一个引用bean行为的命令button,因此总共有三个ELexpression式,然后有效地创build三个实例。 一个用户名被设置,一个用密码设置,另一个用来调用该操作。 你通常只想在这个bean上使用这个范围,它应该和注入的bean一样长。 因此,如果在@SessionScoped注入了@NoneScoped@Dependent ,那么它的存活时间与@SessionScoped bean一样长。

也可以看看:

  • 在时间间隔后过期特定的托pipebean实例
  • 什么是没有范围的bean,什么时候使用它?
  • 什么是JSF 2应用程序中的默认Managed Bean Scope?

Flash范围

最后,JSF也支持Flash范围。 它由一个短的生活cookie支持,与会话范围内的数据input相关联。 在redirect之前,将在HTTP响应中设置一个cookie,其值与会话范围中的数据项唯一关联。 在redirect之后,Flash范围cookie的存在将被检查,并且与cookie相关联的数据条目将从会话范围中被移除并被放置在redirect请求的请求范围中。 最后,cookie将被从HTTP响应中删除。 通过这种方式,redirect的请求可以访问在初始请求中准备的请求范围数据。

这实际上不可用作托pipebean范围,也就是说没有@FlashScoped这样的东西。 Flash范围只能通过托pipebean中的ExternalContext#getFlash()和EL中的#{flash}以地graphics式提供。

也可以看看:

  • 如何在redirect页面显示脸部信息
  • 在@ViewScoped bean之间传递一个对象而不使用GET参数
  • CDI缺less@ViewScoped和@FlashScoped

从JSF 2.x开始,有4个Bean Scopes:

  • @SessionScoped
  • @RequestScoped
  • @ApplicationScoped
  • @ViewScoped

会话范围:会话范围从会话build立到会话终止的时间一直存在。 如果Web应用程序调用HttpSession对象上的invalidate方法,或者超时,会话将终止。

RequestScope:请求范围是短暂的。 它在提交HTTP请求时开始,在响应被发送回客户端之后结束。 如果将托pipebean放入请求范围,则会为每个请求创build一个新实例。 如果您担心会话范围存储的成本,则值得考虑请求范围。

ApplicationScope:应用程序范围持续整个Web应用程序的持续时间。 这个范围是在所有请求和所有会话中共享的。 如果应该在Web应用程序的所有实例之间共享单个Bean,则将托pipe的Bean放入应用程序范围。 该bean是在应用程序的任何用户首次请求时构build的,并且在从应用程序服务器中删除该Web应用程序之前它一直处于活动状态。

ViewScope:在JSF 2.0中添加了视图范围。 在重新显示相同的JSF页面的同时,视图范围内的bean仍然存在。 (JSF规范使用术语视图来表示JSF页面。)只要用户导航到不同的页面,该bean就会超出范围。

根据您的要求select您的范围。

来源: David Geary和Cay Horstmann撰写的Core Java Server Faces第3版 [页码。 51 – 54] 在这里输入图像描述