【问题标题】:Invoke method just before session expires在会话到期之前调用方法
【发布时间】:2011-04-25 23:53:05
【问题描述】:

我的 webapp 有登录的用户。有超时。在会话到期之前,我想执行一个方法来清理一些锁。

我已经实现了sessionListener,但是一旦我到达public void sessionDestroyed(HttpSessionEvent event),会话就已经消失了,我需要从中获取一些数据,所以我想执行一个方法(它需要会话处于活动状态并且能够访问FacesConfig.getCurrentInstance()) 在会话实际过期之前。

我该怎么做?有任何想法吗?这是我的会话监听器:

public class MySessionListener implements HttpSessionListener {

    private static final Logger log = LoggerFactory.getLogger(MySessionListener.class);

    public MySessionListener() {

    }

    public void sessionCreated(HttpSessionEvent event) {
        log.debug("Current Session created : "
              + event.getSession().getId()+ " at "+ new Date());
    }

    public void sessionDestroyed(HttpSessionEvent event) {
        // get the destroying session...

        HttpSession session = event.getSession();
        prepareLogoutInfoAndLogoutActiveUser(session);

        log.debug("Current Session destroyed :"
              + session.getId()+ " Logging out user...");

        /*
         * nobody can reach user data after this point because 
         * session is invalidated already.
         * So, get the user data from session and save its 
         * logout information before losing it.
         * User's redirection to the timeout page will be 
         * handled by the SessionTimeoutFilter.
         */

         // Only if needed
    }

    /**
     * Clean your logout operations.
     */
    public void prepareLogoutInfoAndLogoutActiveUser(HttpSession httpSession) {
        UserBean user = FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{user}", UserBean.class);
        LockBean lock = FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{lock}", LockBean.class);
        lock.unlock(user.getUsername());
        log.info("Unlocked examination for user: "+user.getUsername());
    }
}

但我在FacesContext.getCurrentInstance().getApplication() 得到NullPointerException,因为getCurrentInstance 为空或getApplication 返回空

【问题讨论】:

    标签: java jsf servlets


    【解决方案1】:

    您可以通过实现 HttpSessionBindingListener 来实现,您需要通过调用 registerSession 注册一个持有锁的会话(字符串“sessionBindingListener”可能不会更改)。容器会在会话超时后会话被销毁之前回调valueUnbound()方法。

    public class ObjectLock implements Serializable,HttpSessionBindingListener {
        public void valueBound(HttpSessionBindingEvent event) {
            log.info("valueBound:" + event.getName() + " session:" + event.getSession().getId() );
    
        }
    
        public void registerSession() {
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put( "sessionBindingListener", this  );
            log.info( "registered sessionBindingListener"  );
        }
    
        public void valueUnbound(HttpSessionBindingEvent event) {
            log.info("valueUnBound:" + event.getName() + " session:" + event.getSession().getId() );
                   // add you unlock code here:
            clearLocksForSession( event.getSession().getId() );
        }
    }
    

    【讨论】:

    • 我把它放在UserBean类下,它知道LockBean。我已经从... BalusC :D 回答的上一个问题中实现了这个,所以我只需要添加lock.unlock 行就可以了。谢谢你们。
    • 实现HttpSessionBindingListener确实更好。您只需要确保在 JSF 请求期间调用了 registerSession()(但是,如果 ObjectLock 已经是会话范围的托管 bean,则该方法无用。
    • 如果你有一个SessionBean,你甚至不需要注册另一个监听器并访问SessionMap。由于您的 Bean 已经添加到 SessionMap 中,您可以让它实现 HttpSessionBindingListener 并且 valueUnbound 将直接在 SessionBean 上调用(因为它被框架绑定和取消绑定)
    • 这真的有效吗?文档说“对于无效或过期的会话,会在会话无效或过期后发送通知。”(docs.oracle.com/javaee/5/api/javax/servlet/http/…)
    【解决方案2】:

    一个更优雅的解决方案:

    只需在 Session-Bean 中添加 @PreDestroy 注释!如果 Session 将要被销毁,它会预先在所有 SessionBeans 上调用 PreDestroy,然后你就可以注销了!

    虽然这目前不适用于许多应用程序服务器,但似乎是 JSF 规范中一个不清楚的部分。因此,必须使用已接受的答案 (HttpSessionBindingListener),直到 @PreDestroy 在所有服务器上按预期工作。

    【讨论】:

      猜你喜欢
      • 2013-05-29
      • 1970-01-01
      • 1970-01-01
      • 2016-03-06
      • 2011-12-07
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多