【问题标题】:Why calling invalidate() in HttpSessionListener doesn't give StackOverflowError?为什么在 HttpSessionListener 中调用 invalidate() 不会给出 StackOverflowError?
【发布时间】:2018-07-25 06:27:28
【问题描述】:

我有一个jsp 文件和一个HttpSessionListener 来监控HttpSession 破坏活动。

index.jsp

<%
    HttpSession s = request.getSession();
    System.out.println("SID1 : " + s.getId());
    s.setAttribute("Key", "Value");
    s.invalidate();
%>

会话监听器

@WebListener
public class SessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        HttpSession s = se.getSession();
        System.out.println("SID2 : " + s.getId());
        System.out.println(s.getAttribute("Key"));
        s.invalidate();
        System.out.println("Session Destroyed");
    }

}

现在根据上述情况,向index.jsp发送HTTP请求应该创建一个HttpSession并调用它的invalidate()方法,同时HttpSessionListener应该捕获相同的HttpSession并调用invalidate()再一次,这个过程应该一遍又一遍地重复。

这最终会导致抛出java.lang.StackOverflowError。但我得到了以下输出没有任何错误。

SID1 : A2751AE9E782A17380415B0078C9ED90
SID2 : A2751AE9E782A17380415B0078C9ED90
Value
Session Destroyed

我已经用 GlassFish 和 Tomcat 服务器对其进行了测试,结果保持不变。有人可以解释发生了什么吗?

【问题讨论】:

  • 为什么要抛出StackOverflowErrorHttpSession.invalidate() 上的 Javadocs 提到如果 在已经失效的会话上调用此方法,它应该抛出 IllegalStateException。也许这是您正在使用的特定应用程序服务器的怪癖/错误。
  • 可以在jsp中s.invalidate()之后打印request.getSession().isNew()并告诉我们结果吗?
  • 会话第一次没有失效。查看会话 ID。他们是一样的。所以它应该一次又一次地调用invalidate
  • @techtrainer 在jsp 文件中?
  • 在 jsp 文件中是的,如评论中所述。

标签: java jakarta-ee listener stack-overflow httpsession


【解决方案1】:

显然这是因为当你从public void sessionDestroyed(HttpSessionEvent se) {...}第二次调用invalidate方法时会话已经失效。

Session.beginInvalidate() 在这种情况下返回 false 值并且此块未被调用:

boolean result = beginInvalidate();

try {
    //if the session was not already invalid, or in process of being invalidated, do invalidate
    if (result) {
         //tell id mgr to remove session from all contexts
         _handler.getSessionIdManager().invalidateAll(_sessionData.getId());
    }
}

特别是,_handler.getSessionIdManager().invalidateAll 调用SessionHandler.invalidate,后者调用SessionHandler.removeSession,后者调用_sessionListeners.get(i).sessionDestroyed(event);

因此,如果会话已经失效,这种情况将不起作用。

【讨论】:

  • 如果会话已经失效,为什么在监听器中调用时属性会打印在输出中?
  • 我不明白你的最后一个问题。有什么问题?第一次从 JSP 调用 s.invalidate();。它完成了我的回答中描述的所有这些序列。之后,您的sessionDestroyed 会在执行所有打印输出的地方被调用。然后你再次调用s.invalidate(),但它没有任何效果,因为此时会话已经失效。
猜你喜欢
  • 2014-09-17
  • 2023-01-22
  • 1970-01-01
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 1970-01-01
相关资源
最近更新 更多