我正在尝试使用ServletRequestListener
将RequestId注入Log4j MDC。为了避免内存泄漏,我正在requestDestroyed()
方法中清除我的MDC添加内容。
我使用的是JBoss 4.2.1GA。
但是,我在一个非常具体的用例中遇到了一个特殊问题,其中一个Struts Action正在重定向一个动作。我可以看到调用了requestDestroyed()方法,但重定向的操作没有调用requestInitialized()方法。
public class Log4jMDCRequestListener implements ServletRequestListener {
/**
* Need to clear the MDC parameters at the end of the request as the thread can be reused by another request
*/
@Override
public void requestDestroyed(ServletRequestEvent paramServletRequestEvent) {
MDCUtils.clear();
}
/**
* Inject the necessary trackers into the MDC to use in the log4j loggers
*/
@Override
public void requestInitialized(ServletRequestEvent paramServletRequestEvent) {
HttpServletRequest request = (HttpServletRequest) paramServletRequestEvent.getServletRequest();
// generate a random requestId to correlate all logs from the same request
String requestId = UUID.randomUUID().toString();
MDCUtils.setRequestId(requestId);
MDCUtils.setIP(WebUtil.getRealIP(request));
HttpSession session = request.getSession(false);
if (session != null) {
MDCUtils.setSessionid(session.getId());
}
}
}
在我的web.xml中:
<listener>
<listener-class>webapp.listener.Log4jMDCRequestListener</listener-class>
</listener>
使用fiddler我可以看到我的浏览器在调用requestDestoryed()
方法后向我的应用程序发出新请求,但未触发requestInitialized()
方法。如果我查看正在使用的各个请求对象的对象id,我可以看到它是相同的请求ID。
在没有触发requestInitialized
方法的情况下,容器是否可以重用请求对象?有什么方法可以进一步调试吗?
我的问题是第二个请求以清除的MDC结束(在调用requestDestroyed之后)并且从不重新初始化。
我试图使用Filter而不是Listener,我看到了相同的行为。经过进一步分析,我想我已经注意到这个问题是容器调用登录页面而不是请求本身。
例如,在我的web.xml中:
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.do</form-login-page>
<form-error-page>/login.do?error=true</form-error-page>
</form-login-config>
</login-config>
如果我在登录前尝试访问任何安全页面,容器会将我重定向到login.do表单,并在此过程中将跳过筛选器和侦听器。 (在我的ActionCommandBase
实现中设置一个断点并检查调用堆栈,我可以看到在执行链时没有调用过滤器/监听器。
有什么方法吗?