我在视图 Scoped Bean 中有@PreDestroy
一个带有注释的方法和另一个带有@PostConstruct
注释的方法。
@PostConstruct
每次我导航到使用此视图范围 bean 的页面时,都会正确调用该方法。
但是,当我通过 导航到新页面(不使用此视图范围 bean)时<h:link/>
,永远不会调用该@PreDestroy
方法。
我不是在谈论手动更改 url 或会话结束,只是一个导航案例。
我错过了什么?
提前致谢
我在视图 Scoped Bean 中有@PreDestroy
一个带有注释的方法和另一个带有@PostConstruct
注释的方法。
@PostConstruct
每次我导航到使用此视图范围 bean 的页面时,都会正确调用该方法。
但是,当我通过 导航到新页面(不使用此视图范围 bean)时<h:link/>
,永远不会调用该@PreDestroy
方法。
我不是在谈论手动更改 url 或会话结束,只是一个导航案例。
我错过了什么?
提前致谢
这是设计使然。只有当 POST 操作导致导航不是回发到同一视图时(即操作方法没有返回null
or void
,而是一个 fullworthy String
,即使只是空的),它才会立即被破坏。
<h:link>
生成一个不调用任何 POST 操作的 GET 链接。由于在卸载视图时无法可靠地通过 (XML)HTTP 请求通知服务器端,因此无法通知 JSF 销毁与视图关联的视图范围 bean。在这种情况下,视图范围的 bean 将仅在会话过期或会话中的最大逻辑视图已超过(默认为 15)并且关联视图按顺序排列的第一个时被销毁。
如果您真的想通过导航操作破坏视图范围的 bean,那么您最好的办法是改为将其设为 POST 请求,并通过返回带有参数<h:commandLink>
的导航结果来发出重定向。?faces-redirect=true
但这毕竟不是 SEO 友好的,因为机器人不会索引 POST 链接。
毕竟我不会关心会话中仍然存在的视图。如果您打算进行一些清理或记录,我会根据具体的功能要求寻找替代方法。
从理论上讲,HTML DOM 事件可能会onbeforeunload
发生,但这是一个非标准事件,并且浏览器行为未指定在该事件期间发送 ajax 请求时会发生什么。它有时会到达,但有时也不会。
更新:实际上,自 OmniFaces 2.2 以来,这已在OmniFaces中实现。@ViewScoped
最初在同步 XHR的帮助下,从 OmniFaces 2.6 开始,在beacon的帮助下。它在主流浏览器中运行良好。从 OmniFaces 2.3 开始,它甚至会立即销毁相关的 JSF 服务器端视图状态,而从 OmniFaces 2.6 开始,它甚至会立即销毁物理 bean,从而进一步减少不必要的内存使用。另请参阅JSF:Mojarra 与 OmniFaces @ViewScoped:@PreDestroy 已调用但 bean 不能被垃圾收集
我准备了一个小型 NetBeans 项目,演示 JSF2.2 CDI 兼容的 @ViewScoped bean (javax.faces.view.ViewScoped) 何时在不同的导航案例(对于 Mojarra 2.2.9、Glassfish4、NetBeans8.0.2、JDK1 .7),可在此处下载。代码在此省略,请看下载。
此图像总结了处理的导航案例和结果:
要监视 @ViewScoped bean,请针对 Glassfish(或迷你项目上的内置 NetBeans 分析器)使用 VisualVM,并在包名称“webel.com.jsf”上过滤采样器内存堆直方图类视图。下图显示了一个荒谬的 66 个 webel.com.jsf.Jsf22ViewBean 实例,在对 h:link、浏览器 URL GET 和浏览器 RELOAD GET 进行了大量试验后,哪些实例不会被垃圾收集(您可以使用 VisualVM Perform GC 进行测试)按钮):
相比之下,使用 h:commandButton 和操作方法表达式或操作字符串导致 @ViewScoped bean 被释放以进行垃圾回收(WeldClientProxy 始终有一个对 @ViewScoped bean 的引用,并且当您使用 h:commandButton 来回导航时,WeldClientProxy 从一个可释放 bean 移动到下一个) .