在没有用户注销的情况下,Http会话正在被销毁

时间:2016-09-14 10:51:13

标签: java session garbage-collection

我们不时会在日志中看到这一点:

2016-09-14 10:43:04,183 [ContainerBackgroundProcessor[StandardEngine[Catalina]]] INFO  HttpSessionListener - User Username logged out

这一行来自我们的自定义HttpSessionListener中的以下代码:

/* (non-Javadoc)
     * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
     */
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {

        HttpSession session = httpSessionEvent.getSession();
        UserContainer userContainer = (UserContainer) session.getAttribute(UserContainer.DEFAULT_SESSION_ATTRIBUTE);
        if(userContainer != null) {
            LoginView loginView = userContainer.getLoginView();
            // A REST client may do a failed login after witch it has a session and a UserContainer with a null loginView. 
            if (loginView != null) {
                String userId = loginView.getUserId();
                String userName = loginView.getUserName();
                // remove the user container from the UserContainerManager
                UserContainerManager.getInstance().removeUserContainer(userContainer);
                // log logout event
                LOGGER.info(String.format("User %s - %s logged out", userId, userName));
            } else {
                // remove the user container from the UserContainerManager
                UserContainerManager.getInstance().removeUserContainer(userContainer);
                // Failed login already logged by the LoginService.
            }

        }
    }

我们会话管理的一些背景信息:我们的会话中有一个UserContainer类,因此我们可以将所有与用户相关的信息保存在一个对象中。该对象还包含对会话的瞬态引用。

public class UserContainer implements HttpSessionBindingListener, HttpSessionActivationListener,
        Serializable {

    // HttpSession associated with this UserContainer :
    private transient HttpSession httpSession;

    /**
     * The container calls this method when it is being bound to the session.
     *
     * @param event the event that identifies the session
     */
    public void valueBound(HttpSessionBindingEvent event) {
        httpSession = event.getSession();
    }

    /**
     * Notifies the object that it is being unbound from a session. Used here
     * to remove the userid from the list of the logged in users when a
     * session has expired.
     *
     * @param e the event that identifies the session
     */
    public void valueUnbound(HttpSessionBindingEvent e) {
    }

    /**
     * Invalidate the httpSession of this user.
     */
    public void invalidateHttpSession() {
        httpSession.invalidate();
    }

    /**
     * @return the httpSession for this user.
     */
    public HttpSession getHttpSession() {
        return httpSession;
    }
}

当我们获得上述行时,被引用的用户保持连接,但大多数操作都失败了,他们必须再次登录。他们的UserContainer对象被销毁,但他们的会话仍然存在。

我个人认为这是因为他们的UserContainer中的httpSession对象正在获取GC,触发sessionDestroyed事件并销毁他们的UserContainer。然而,我的同事说,由于Java是一个ByRef语言,UserContainer中GC的httpSession对象也应该是GC的UserContainer所在的httpSession,这不会发生,因为用户不会被抛回到下次请求登录界面。

是什么导致这种情况?

0 个答案:

没有答案