为什么过期的@ViewScoped bean在会话到期之前不会被销毁

时间:2014-01-05 05:20:23

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

我在使用Java 7的GlassFish 4上使用Mojarra 2.2.4。

据我所知,从BalusC对How and when is a @ViewScoped bean destroyed in JSF?的回答中,@ ViewScoped bean应该在三种情况下销毁:

  1. 回复非空结果
  2. 会话到期
  3. 超出会话的最大逻辑视图数
  4. 我的bean在前两种情况下被销毁,但是在超过最大逻辑视图数时却没有。我已经验证,当超过最大值时,bean会 expire (我得到一个ViewExpiredException),但是在会话本身到期之前它们仍然没有被销毁

    出于内存消耗的原因,我想在第三种情况下销毁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确认UIViewRoot的ViewMap仍然引用了bean。在我的全尺寸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 beans 在会话到期时被销毁,与Linked ViewScoped beans lead to memory leaks

    等相关问题中描述的问题不同

    询问为什么每个bean在后续刷新时不会立即销毁 ,如下所示:JSF 2.1 ViewScopedBean @PreDestroy method is not called。我想知道为什么即使它们过期并且不再有用,它们仍然没有被破坏,因此继续消耗内存。

1 个答案:

答案 0 :(得分:1)

我能够通过使用OmniFaces @ViewScoped注释(org.omnifaces.cdi.ViewScoped)而不是标准的@ViewScoped(javax.faces.view.ViewScoped)找到一个干净的解决方法。

OmniFaces ViewScoped一旦到期就会正确销毁bean。

请点击此处了解更多详情: http://showcase.omnifaces.org/cdi/ViewScoped