2016-06-28 2 views
1

Я пытаюсь регистрировать сообщение всякий раз, когда уничтожается HTTP-сессия. Я использую Весенняя ботинок, весенняя безопасность и Tomcat 8 (встроенный) в этом веб-приложении.Метод HttpSessionListener.sessionDestroyed() вызывается дважды во время таймаута сеанса

В течение таймаута сеанса sessionDestroyed() метод получает вызванное 2 раза, поэтому мое сообщение регистрируется дважды.

Я проверил идентификатор сеанса и идентификатор сеанса 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"); 
    } 
} 

Нижняя строка, добавляющая текущий слушатель в контекст сервлета.

getServletContext().addListener(this); 

Как Spring уже добавили этот приемник (MySessionListener) в Servlet контексте, добавив слушателя для 2-й раз этилированный во 2-й sessionDestroyed() вызов метода по классам org.apache.catalina.session.StandardSession Tomcat.

Исходный код 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();