Spring HttpSessionListener.sessionDestroyed()方法在会话超时期间被调用两次
每当HTTP会话被破坏时,我都试图记录一条消息。 我在这个web应用程序中使用了Spring引导、Spring安全和Tomcat 8(嵌入式)Spring HttpSessionListener.sessionDestroyed()方法在会话超时期间被调用两次,spring,servlets,tomcat8,Spring,Servlets,Tomcat8,每当HTTP会话被破坏时,我都试图记录一条消息。 我在这个web应用程序中使用了Spring引导、Spring安全和Tomcat 8(嵌入式) @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (applicationContext instanceof WebApplicationContext) {
@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");
}
}
在会话超时期间,sessionDestroyed()方法被调用了两次,因此我的消息被记录了两次
我检查了会话ID,在两次调用期间,会话ID相同
这就是我的代码的样子
import org.springframework.security.core.session.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());
}
任何帮助都将不胜感激
注意:我注意到这个问题是Tomcat5中的一个缺陷,我不认为这个缺陷在Tomcat8中还没有修复
参考资料:这不是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");
}
}
我在我的应用程序中发现以下代码
@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);
由于Spring已经将这个监听器(MySessionListener)添加到Servlet上下文中,第二次添加监听器导致Tomcat的org.apache.catalina.session.StandardSession类调用第二个sessionDestroyed()方法
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);
}
....
....