2016-06-28 377 views
1

我试图在HTTP会话销毁时记录消息。 我在这个Web应用程序中使用Spring Boot,Spring Security和Tomcat 8(嵌入式)。HttpSessionListener.sessionDestroyed()方法在会话超时期间被调用两次

在会话超时期间,sessionDestroyed()方法被调用2次,所以我的消息被记录了两次。

我在两次调用期间都检查了会话ID和会话ID是SAME

这是我的代码看起来像......

import org.springframework.security.core.session.SessionRegistry; 

...

 @Component 
     public class MySessionListener implements javax.servlet.http.HttpSessionListener, ApplicationContextAware { 
      @Autowired(required = false) 
      SessionRegistry sessionRegistry; 

和sessionDestroyed()如下。

@Override 
    public void sessionDestroyed(HttpSessionEvent se) { 
     HttpSession session = se.getSession(); 

     SecurityContextImpl springSecurityContext = (SecurityContextImpl)session.getAttribute("SPRING_SECURITY_CONTEXT"); 
     if(springSecurityContext!=null){ 
      Authentication authentication = springSecurityContext.getAuthentication(); 
      LdapUserDetails userDetails = (LdapUserDetailsImpl)authentication.getPrincipal(); 

      WebAuthenticationDetails WebAuthenticationDetails = (WebAuthenticationDetails)authentication.getDetails(); 
      String userIp = WebAuthenticationDetails.getRemoteAddress(); 

      Log.info(userDetails.getUsername(),userIp,timestamp,"timeout or logout","session destroyed"); 

     } 

     sessionRegistry.removeSessionInformation(se.getSession().getId()); 
     logger.info("Due to timeout/logout Session is Destroyed : Session ID is..." + session.getId()); 

    } 

任何帮助将不胜感激...

注:我注意到这个问题是一个缺陷的Tomcat 5,我不认为缺陷是仍然在Tomcat中8不固定。

参考:https://bz.apache.org/bugzilla/show_bug.cgi?id=25600

回答

0

这不是Tomcat的错误。这是一个特定于我的应用程序的错误。

我在我的应用程序中找到了下面的代码。

@Override 
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
    if (applicationContext instanceof WebApplicationContext) { 
     ((WebApplicationContext) applicationContext).getServletContext().addListener(this); 
    } else { 
     //Either throw an exception or fail gracefully, up to you 
     throw new RuntimeException("Must be inside a web application context"); 
    } 
} 

在Servlet上下文中添加当前监听器。

getServletContext().addListener(this); 

由于春天已经加入这个监听器(MySessionListener)成Servlet上下文,添加的侦听含铅进入第二sessionDestroyed()由Tomcat的org.apache.catalina.session.StandardSession类方法调用中的第二次。

Tomcat的源代码仅供参考。

package org.apache.catalina.session; 

public class StandardSession implements HttpSession, Session, Serializable { 

.... 

public void expire(boolean notify) { 

..... 

..... 

Object listeners[] = context.getApplicationLifecycleListeners(); 
        if (listeners != null && listeners.length > 0) { 
         HttpSessionEvent event = 
          new HttpSessionEvent(getSession()); 
         for (int i = 0; i < listeners.length; i++) { 
          int j = (listeners.length - 1) - i; 
          if (!(listeners[j] instanceof HttpSessionListener)) 
           continue; 
          HttpSessionListener listener = 
           (HttpSessionListener) listeners[j]; 
          try { 
           context.fireContainerEvent("beforeSessionDestroyed", 
             listener); 
           listener.sessionDestroyed(event); 
           context.fireContainerEvent("afterSessionDestroyed", 
             listener); 
          } 

.... 
.... 

从上面的Tomcat源代码两者..

所以,听众[]包含MySessionListener的重复条目。

Object listeners[] = context.getApplicationLifecycleListeners();