为什么在 HttpSessionListener 中调用 invalidate() 不会给出 StackOverflowError?

Why calling invalidate() in HttpSessionListener doesn't give StackOverflowError?

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

index.jsp

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

SessionListener

@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.WhosebugError。但是我得到了以下输出 ,没有任何错误。

SID1 : A2751AE9E782A17380415B0078C9ED90
SID2 : A2751AE9E782A17380415B0078C9ED90
Value
Session Destroyed

我已经用 GlassFish 和 Tomcat 服务器对其进行了测试,结果保持不变。谁能解释一下这是怎么回事?

显然这是因为当您从 public void sessionDestroyed(HttpSessionEvent se) {...}.

第二次调用 invalidate 方法时会话已经失效

Session.beginInvalidate() returns 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);

因此,如果会话已经失效,则此方案不起作用。