不调用 JSF 2.1 ViewScopedBean @PreDestroy 方法

Posted

技术标签:

【中文标题】不调用 JSF 2.1 ViewScopedBean @PreDestroy 方法【英文标题】:JSF 2.1 ViewScopedBean @PreDestroy method is not called 【发布时间】:2011-10-07 06:31:44 【问题描述】:

我在视图 Scoped Bean 中有一个带有 @PreDestroy 注释的方法和另一个带有 @PostConstruct 注释的方法。

每次我导航到使用此视图范围 bean 的页面时,都会正确调用 @PostConstruct 方法。

但是,当我通过 <h:link/> 导航到新页面(不使用此视图范围 bean)时,永远不会调用 @PreDestroy 方法。

我说的不是changing manually the url or the end of the session,只是一个导航案例。

我错过了什么?

提前致谢

【问题讨论】:

【参考方案1】:

这是设计使然。只有当 POST 操作导致导航不是回发到同一视图时(即操作方法没有返回 nullvoid,而是完全值得的 String,即使当只是空的)。

<h:link> 生成一个不调用任何 POST 操作的 GET 链接。由于在卸载视图时无法可靠地通过 (XML)HTTP 请求通知服务器端,因此无法通知 JSF 销毁与视图关联的视图范围 bean。在这种情况下,视图范围的 bean 将仅在会话过期或会话中的最大逻辑视图已超过(默认为 15)并且关联视图按顺序排列的第一个时被销毁。

如果您真的想通过导航操作破坏视图范围的 bean,那么最好的办法是通过 <h:commandLink> 将其设为 POST 请求,并通过返回导航结果发出重定向带有?faces-redirect=true 参数。但这毕竟不是 SEO 友好的,因为机器人不会索引 POST 链接。

我毕竟不在乎视图仍在会话中。如果您打算进行一些清理或记录,我会根据具体的功能要求寻找替代方法。

theory 中,html DOM onbeforeunload 事件是可能的,但这是一个非标准事件,浏览器行为未指定在此期间发送 ajax 请求时会发生什么事件。它有时会到达,但有时也不会。

更新:在实践中,自 OmniFaces 2.2 起,这已在 OmniFaces @ViewScoped 中实现。最初在synchronous XHR 的帮助下,从OmniFaces 2.6 开始,在beacon 的帮助下。它在主流浏览器中运行良好。从 OmniFaces 2.3 开始,它甚至会立即销毁相关的 JSF 服务器端视图状态,而从 OmniFaces 2.6 开始,它甚至会立即销毁物理 bean,从而进一步减少不必要的内存使用。另请参阅JSF: Mojarra vs. OmniFaces @ViewScoped: @PreDestroy called but bean can't be garbage collected

【讨论】:

需要做一个小的修正。即使您进行了重定向,如果您重定向到与 POST 请求来源相同的视图,JSF 也不会破坏视图范围的 bean。对于要销毁的视图范围 bean,您需要在处理 POST 请求后完全呈现不同的视图。 如果我理解得很好,使用信标,离开视图的@PreDestroy 可能会在新加载的视图的@PostConstruct 之后调用? @ForguesR:是的,它是彼此异步的。【参考方案2】:

我准备了一个小型 NetBeans 项目,演示 JSF2.2 CDI 兼容的 @ViewScoped bean (javax.faces.view.ViewScoped) 何时在不同的导航案例(对于 Mojarra 2.2.9、Glassfish4、NetBeans8. 0.2,JDK1.7),可用于download here。 此处省略代码,请看下载。

处理的导航案例和结果通过这张图总结:

要监视 @ViewScoped bean,请针对 Glassfish(或迷你项目中的内置 NetBeans 分析器)使用 VisualVM,并在包名称“webel.com.jsf”上过滤采样器内存堆直方图类视图。下图显示了一个荒谬的 66 个实例 webel.com.jsf.Jsf22ViewBean 在大量试验 h:link、浏览器 URL GET 和浏览器 RELOAD GET 之后,哪些实例不会被垃圾收集(您可以使用 VisualVM 执行 GC 按钮进行测试):

相比之下,使用 h:commandButton 和 action 方法从 index.xhtml(一次使用 @ViewScoped bean 进行简单的 EL 变量读取)导航到 done.xhtml(根本不使用 bean)表达式或操作字符串导致 @ViewScoped bean 被释放以进行垃圾收集(WeldClientProxy 始终有一个引用到 @ViewScoped bean,并且当您使用 h:commandButton 来回导航时,WeldClientProxy 从一个可释放 bean 移动到下一个)。

【讨论】:

以上通过详尽地展示各种导航案例回答了这个问题(进一步建立在 BalusC 的答案之上),但它没有解释如何处理生成的不会垃圾的“悬空”@ViewScoped bean收集:我在这里问一个问题:***.com/questions/30410601/…

以上是关于不调用 JSF 2.1 ViewScopedBean @PreDestroy 方法的主要内容,如果未能解决你的问题,请参考以下文章

为啥 UIComponent.setStyleClass() 在 JSF 2.1 转换器中不起作用?

JSF 2.1 条件字段验证

在 JBoss 5.1.1 上将 JSF 从 1.2 升级到 2.1

JSF2 <h:selectOneMenu 和 <f:ajax 侦听器在 PrettyFaces 过滤器导航之后未调用

如何在 Oracle Weblogic 12.1 中部署 JSF 2.1 webapp?

JSF 1.1-不刷新页面调用backing bean的动作方法(通过ajax/javascript)