Java 在会话到期之前调用方法

Java 在会话到期之前调用方法,java,jsf,servlets,Java,Jsf,Servlets,我的webapp有登录的用户。有一个超时。在会话到期之前,我想执行一个方法来清理一些锁 我已经实现了一个sessionListener,但是一旦我到达public void sessionDestroyed(HttpSessionEvent事件)会话就已经结束了,我需要从中获取一些数据,所以我想执行一个方法(该方法需要会话处于活动状态,并且能够访问FacesConfig.getCurrentInstance())在会话实际过期之前 我该怎么做?有什么想法吗?这是我的会话侦听器: public c

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

我已经实现了一个
sessionListener
,但是一旦我到达
public void sessionDestroyed(HttpSessionEvent事件)
会话就已经结束了,我需要从中获取一些数据,所以我想执行一个方法(该方法需要会话处于活动状态,并且能够访问
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
为null或者
getApplication
返回null

可以通过实现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() );
    }
}

还有一个优雅的解决方案:

只需向会话Bean添加一个
@PreDestroy
注释!如果会话将被销毁,它将提前调用所有SessionBean上的PreDestroy,在那里您可以注销和执行所有操作


尽管这在很多应用服务器上都不起作用,但JSF规范中似乎有一个不明确的部分。因此,有必要使用公认的答案(HttpSessionBindingListener),直到@PreDestroy在所有服务器上都能正常工作。

我把它放在
UserBean
类下,它知道
LockBean
。我在前面的问题中已经实现了这一点,答案是…BalusC:D,所以我只需要添加
lock.unlock
行,它就工作了。谢谢你们两位。实现
HttpSessionBindingListener
确实更好。您只需要确保在JSF请求期间调用
registerSession()
(但是,如果
ObjectLock
已经是会话范围的托管bean,那么该方法是无用的。如果您有一个SessionBean,您甚至不需要注册另一个侦听器并访问SessionMap。因为您的bean已经添加到SessionMap,您可以让它实现HttpSessionBindingListener,valueUnbound将在t上调用。)SessionBean直接(因为它被框架绑定和解除绑定)这真的有效吗?文档中说“对于失效或过期的会话,在会话失效或过期后发送通知。”()