2016-06-28 1 views
1

HTTP 세션이 삭제 될 때마다 메시지를 기록하려고합니다. 이 웹 응용 프로그램에 스프링 부트, 스프링 보안 및 톰캣 8 (포함)을 사용하고 있습니다.HttpSessionListener.sessionDestroyed() 메서드가 세션 시간 초과 중에 두 번 호출됩니다.

세션 시간 초과시 sessionDestroyed() 메서드가 2 번 호출되어이되어 내 메시지가 두 번 기록됩니다.

세션 ID를 확인하고 두 번의 호출 중에 세션 ID가 같음입니다.

이 내 코드 같은 모습입니다 ...

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()); 

    } 

어떤 도움을 이해할 수있을 것이다 ... : 나는이 문제를 발견 내가 결함이 여전히 톰캣 8 고정되지 않은 것을 생각하지 않는다, 톰캣 5에 결함이었다.

참조 : 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"); 
    } 
} 

이하는 현재 수신기를 서블릿 컨텍스트에 추가하는 것입니다.

getServletContext().addListener(this); 

으로 봄은 이미 2 sessionDestroyed() Tomcat의 org.apache.catalina.session.StandardSession 클래스로 메소드 호출에 납이 함유 된 2 시간 동안 청취자를 추가, 서블릿 컨텍스트에이 리스너 (MySessionListener)를 추가했다.

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); 
          } 

.... 
.... 

톰캣의 소스 코드를 위에서 찍은 ..

그래서, 청취자는 [] MySessionListener의 중복 항목이 포함되어 있습니다.

Object listeners[] = context.getApplicationLifecycleListeners();