会话过期后未调用 @PreDestroy

Posted

技术标签:

【中文标题】会话过期后未调用 @PreDestroy【英文标题】:@PreDestroy not called after session expired 【发布时间】:2013-01-22 07:32:28 【问题描述】:

这是一个在 WAS8.0 上运行的 JSF 2 应用程序。这是一页的“支持”bean的代码。

    @Named("mySessionBean")
    @SessionScoped
    @Stateful
    @LocalBean
    @StatefulTimeout(unit = TimeUnit.MINUTES, value = 10)
    public class MySessionBean implements Serializable 
        @PostConstruct
        public void init()
        
             System.out.println("start MySessionBean: " + this.hashCode());
         

        @PreDestroy
        public void cleanup()
        
             System.out.println("destroy MySessionBean: " + this.hashCode());
         
        ....
    

web.xml 中设置的会话超时值小于 bean 的超时值。当我运行应用程序时,我看到了来自@PostConstruct 的打印输出,但从未看到来自@PreDestroy 的打印输出。我尝试了以下 2 种情况: 1. 注销 - invalidateSession; 2. 只需等到会话到期。

我不是应用程序的设计者。设计者坚持把所有的backing bean作为一个有状态的session bean。我认为更主流的方法就是让它们成为 CDI bean。但无论如何,当我只将注释更改为 CDI 时,我也开始从 @PreDestroy 获取打印输出

    @Named("mySessionBean")
    @SessionScoped
    public class MySessionBean implements Serializable 
    .....

我的问题是,在第一种情况下我没有得到 @PreDestroy 方法调用的原因是什么?如果我看不到 @PreDestroy 被调用,是否有任何其他方法可以跟踪“支持”bean(在本例中为有状态会话 bean)的生命周期。谢谢!

【问题讨论】:

【参考方案1】:

查看Java EE 6 Tutorial 的这一部分,它显示了有状态会话bean 的生命周期。 PreDestroy 方法仅在从客户端代码中显式删除 bean 时调用,调用带有 @Remove 注释的方法。

【讨论】:

我认为使客户端会话无效或会话超时会自动触发@Remove codeFacesContext.getCurrentInstance().getExternalContext().invalidateSession()code。但听起来好像不会。那么以集中方式调用@Remove 方法最好呢? 另外,即使是 InvalidateSession 调用也不会触发 @Remove。但是在那之后,一旦满足 StatefulTimeout 值,PreDestory 不应该在那之后的某个地方被调用吗?我一直在检查会话超时后的日志小时数,但没有找到 PreDestroy 的输出。 规范只是说,在达到超时时,bean 变得有资格删除,由应用程序服务器决定要做什么。如果您需要确定调用 PreDestroy 方法,则应调用 @Remove 方法。 如果我只将服务对象设为 SFSB,并将所有支持 bean 设为 SessionScoped CDI bean。然后将服务对象注入每个支持 bean。当会话到期时,我是否应该从每个注入了服务对象的支持 bean 中调用 @Remove 方法。还是一个就够了?最佳做法是什么? 当您需要存储一些数据并在多个方法调用中持久保存它们时,应该使用有状态会话 bean,通常是在客户端会话期间。他的意思是,标记会话边界并决定何时关闭 sfsb 是应用程序的责任。换句话说,您的问题的解决方案是一个设计良好的工作流程,只有一个出口点;未能满足此要求意味着 sfsbs 不是正确的选择。【参考方案2】:

另一个答案链接到Java EE 6 Tutorial,它甚至没有提到超时的存在。我也不认为该教程明确指出 @PreDestroy 方法仅在显式 @Remove 方法调用之后调用。没有说明因果关系,只是描述了两个事件,不一定直接相关:

在生命周期结束时,客户端调用注解为@Remove 的方法,EJB 容器调用注解为@PreDestroy 的方法(如果有)。

WebSphere docs 提及以下内容:

当调用 remove 方法时,会为有状态会话 bean 调用 PreDestroy 生命周期拦截器回调。还要记住,如果有状态会话 bean 在处于被动状态时超时,或者如果在对 bean 的方法调用期间发生意外异常并且 bean 被丢弃,则不会调用 PreDestroy 生命周期拦截器回调。

现在这里明确声明 PreDestroy 回调在 调用 remove 方法时被调用。同时它明确指出,如果 SFSB 在被动状态下超时,则不会调用 PreDestroy 回调。那么这是否意味着当 SFSB 不处于被动状态时它们会被调用?

现在让我们来看看 JBoss。 首先,有一个JBoss issue 关于 PreDestroy 如果removingTimeout 其次,我刚刚在 JBoss 4.3 上进行了测试,当钝化的 SFSB 在超时时被移除时会发生什么 - 它在销毁之前被激活。

因此,对于超时和 bean 移除的行为方式似乎存在多种解释。

【讨论】:

WebSphere 更新答案:我做了一些测试,当@StatefulTimeout 过期时,WAS 8.5.5.1 将首先调用 PrePassivate,然后销毁 Stateful bean,而不调用 PreDestroy。根据规范 - 2.3.2 生命周期图 - 这是正确的,因为当 SFSB 处于被动状态时,您不必在超时时调用 PreDestroy。但是应该在文档中明确说明超时会在销毁之前钝化bean。

以上是关于会话过期后未调用 @PreDestroy的主要内容,如果未能解决你的问题,请参考以下文章

会话过期的 laravel 事件监听器,因为会话过期时没有调用注销事件监听器

Spring Redis - 主条目过期后未删除索引

即使会话过期,Laravel API 调用也会继续

标头重定向后未定义PHP会话索引?

如何在 Spring MVC-Spring Security 应用程序中处理 GWT RPC 调用的会话过期异常

如何防止会话在顶点过期?