【问题标题】: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 应该在三种情况下被销毁:

  1. 具有非空结果的回发
  2. 会话到期
  3. 已超出会话中的最大逻辑视图数

我的 bean 在前两种情况下被销毁,但在超过最大逻辑视图数时不会。我已经验证了 bean 在超过最大值时会 expire(我得到一个 ViewExpiredException),但在会话本身过期之前它们仍然没有被销毁。

出于内存消耗的原因,我希望在第三种情况下销毁 bean,特别是因为它们在到期后无法使用。

问题

  • 为什么 bean 过期后没有销毁?
  • 这是错误还是预期行为?
  • 什么是干净的解决方法来确保 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。我想知道为什么即使它们过期并且不再有用,它们仍然没有被销毁,从而继续消耗内存。

【问题讨论】:

    标签: jsf-2 managed-bean mojarra jsf-2.2 view-scope


    【解决方案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 只是有个误会。忽略不正确的短语。我从来没有在任何地方说过。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 2018-06-14
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多