为啥在会话过期之前过期的@ViewScoped bean 不会被销毁
Posted
技术标签:
【中文标题】为啥在会话过期之前过期的@ViewScoped bean 不会被销毁【英文标题】:Why are expired @ViewScoped beans not destroyed until the session expires为什么在会话过期之前过期的@ViewScoped bean 不会被销毁 【发布时间】:2014-01-22 16:50:27 【问题描述】:我在带有 Java 7 的 GlassFish 4 上使用 Mojarra 2.2.4。
从 BalusC 对How and when is a @ViewScoped bean destroyed in JSF? 的回答中了解到,@ViewScoped bean 应该在三种情况下被销毁:
-
具有非空结果的回发
会话到期
已超出会话中的最大逻辑视图数
我的 bean 在前两种情况下被销毁,但在超过最大逻辑视图数时不会。我已经验证了 bean 在超过最大值时会 expire(我得到一个 ViewExpiredException),但在会话本身过期之前它们仍然没有被销毁。
出于内存消耗的原因,我希望在第三种情况下销毁 bean,特别是因为它们在到期后无法使用。
问题
为什么 bean 过期后没有销毁? 这是错误还是预期行为? 什么是干净的解决方法来确保 bean 被销毁? 更新: OmniFaces ViewScoped annotation 在 bean 过期后立即销毁它们。小例子
这是我的豆子:
@javax.inject.Named("sandboxController")
@javax.faces.view.ViewScoped
public class SandboxController implements Serializable
private static final Logger log = Logger.getLogger(SandboxController.class.getName());
@PostConstruct
public void postConstruct()
log.log(Level.INFO, "Constructing SandboxController");
@PreDestroy
public void preDestroy()
log.log(Level.INFO, "Destroying SandboxController");
public String getData()
return "abcdefg";
还有我的 sandbox.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<body>
<h:form>
<h:outputText value="#sandboxController.data"/>
</h:form>
</body>
</html>
以及我的 web.xml 的一部分:
<context-param>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>3</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>3</param-value>
</context-param>
如果我刷新 sandbox.xhtml 50 次,我会在日志中获得 50 个 INFO: Constructing SandboxController
副本。无论我刷新多少次,bean 都不会被破坏。 VisualVM 确认 bean 仍然被 UIViewRoot 的 ViewMap 引用。在我的全尺寸 bean 中,它保持了相当多的状态,我很快得到了 OutOfMemoryException。
当我手动使会话过期时,我得到了 50 个 INFO: Destroying SandboxController
的副本。
如果我向 sandbox.xhtml 添加一个提交按钮并将其加载到 4 个不同的选项卡中,然后尝试提交第一个选项卡,我得到一个 ViewExpiredException,正如预期的那样,但 bean 仍然没有被破坏。
如果我改用 javax.faces.bean.ManagedBean 和 javax.faces.view.ViewScoped 注释,行为是相同的。但是,OmniFaces 注释 org.omnifaces.cdi.ViewScoped 可以正常工作。
澄清...
我的@ViewScoped bean正在在会话到期时被销毁,这与Linked ViewScoped beans lead to memory leaks等相关问题中描述的问题不同
我不询问为什么每个 bean 在随后的刷新时没有被销毁立即,如下所示:JSF 2.1 ViewScopedBean @PreDestroy method is not called。我想知道为什么即使它们过期并且不再有用,它们仍然没有被销毁,从而继续消耗内存。
【问题讨论】:
【参考方案1】:我能够通过使用 OmniFaces @ViewScoped 注释 (org.omnifaces.cdi.ViewScoped
) 而不是标准的 @ViewScoped (javax.faces.view.ViewScoped
) 找到一个干净的解决方法。
OmniFaces ViewScoped 会在 bean 过期后立即正确销毁它们。
更多详情请看这里: http://showcase.omnifaces.org/cdi/ViewScoped
【讨论】:
在我的测试中,我注意到在这种特定情况下的行为存在明显差异。你能指出你所指的具体评论吗?何时销毁过期bean的选择可能取决于实现,这样虽然两个库都符合相同的API并因此具有“相同的生命周期”,当过期的 bean 被销毁时,它们仍然会有所不同。 Mahmoud 只是有个误会。忽略不正确的短语。我从来没有在任何地方说过。以上是关于为啥在会话过期之前过期的@ViewScoped bean 不会被销毁的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Quickblox iOS SDK 中检查会话是不是有效或过期?
chrome会话cookie显示过期时间为1969-12-31T23:59:59.000Z