5

我最近发现了在记录时使用MDC的魔力。它完美地工作。

我有以下方法:

public static final String MDC_CLIENT="client";
public static final String MDC_SESSION="session";
public static final String MDC_DEVICE="device";

// Called for every request.
public static void request(final HttpServletRequest request) {
  // The MDC is a thread-local storage accessable from the log formatter.
  MDC.put(MDC_CLIENT, String.format("%s:%s", request.getRemoteHost(), request.getRemotePort()));
  HttpSession session = request.getSession();
  MDC.put(MDC_SESSION, session.getId());
  MDC.put(MDC_DEVICE, (String)session.getAttribute("device"));
  // Also record the context.
  setContext(session.getServletContext());
}

这被称为每个 jsp 中的第一个操作。这使我可以很好地跟踪日志中的会话细节。

但是 - 我怎么知道remove这些地图条目的时间?我应该注意什么事件才能让我整理地图?

我在Tomcat下托管。如果它重用线程,那么我不会泄漏内存,因为它们本质上是线程本地的,所以每个线程put都会覆盖put上次使用线程时的旧线程。如果它没有 - 或者我托管在其他没有的东西下 - 我基本上可能会永远增长地图 - 或者至少在主机重新启动之前。

我认为我的问题的本质是 - 我是否可以检测到表明特定会话或线程已完成并即将被释放的事件。

4

1 回答 1

8

我不会在每个 JSP 中调用,而是注册一个ServletRequestListener,它会在请求开始和完成时得到通知:

public class MDCListener implements ServletRequestListener {
  public void requestInitialized(ServletRequestEvent e) {
    YourUtilityClass.request((HttpServletRequest)e.getServletRequest());
  }

  public void requestDestroyed(ServletRequestEvent e) {
    YourUtilityClass.tearDown((HttpServletRequest)e.getServletRequest());
  }
}

或者,您可以使用过滤器来环绕通常的请求处理流程:

void doFilter(ServletRequest request, ServletResponse response,
              FilterChain chain) throws IOException, ServletException {
  setupMDC();
  chain.doFilter(request, response);
  tearDownMDC();
}

无论哪种方式,您只需在其中注册相关类,web.xml容器应该负责其余的工作。

于 2014-01-15T12:43:05.427 回答