HttpSessionListener.sessionDestroyed() 方法在会话超时期间被调用两次
HttpSessionListener.sessionDestroyed() method is getting called twice during Session timeout
我正在尝试在 HTTP 会话被破坏时记录一条消息。
我在此 Web 应用程序中使用 Spring 启动、Spring 安全和 Tomcat 8(嵌入式)。
在会话超时期间,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());
}
任何帮助将不胜感激...
注意: 我注意到这个问题是 Tomcat 5 中的一个缺陷,我不认为这个缺陷是Tomcat 8.
中仍未修复
这不是 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);
因为 Spring 已经添加 这个监听器 (MySessionListener) 到 Servlet 上下文中,第二次添加监听器导致 [=33 调用第二次 sessionDestroyed() 方法=]的org.apache.catalina.session.StandardSessionclass.
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..
以上源代码
因此,listeners[] 包含 MySessionListener 的重复条目。
Object listeners[] = context.getApplicationLifecycleListeners();
我正在尝试在 HTTP 会话被破坏时记录一条消息。 我在此 Web 应用程序中使用 Spring 启动、Spring 安全和 Tomcat 8(嵌入式)。
在会话超时期间,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());
}
任何帮助将不胜感激...
注意: 我注意到这个问题是 Tomcat 5 中的一个缺陷,我不认为这个缺陷是Tomcat 8.
中仍未修复这不是 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);
因为 Spring 已经添加 这个监听器 (MySessionListener) 到 Servlet 上下文中,第二次添加监听器导致 [=33 调用第二次 sessionDestroyed() 方法=]的org.apache.catalina.session.StandardSessionclass.
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..
以上源代码因此,listeners[] 包含 MySessionListener 的重复条目。
Object listeners[] = context.getApplicationLifecycleListeners();