首页 > 解决方案 > 如何在 Spring Boot Tomcat 场景中清除线程上下文?

问题描述

我们实现了HandlerInterceptor在方法内部设置 MDC 线程上下文数据preHandle

然后我们将这些数据用于日志记录和度量目的。

MDC.clear()但是,如果我们在方法内部清除 MDC 数据afterCompletion,那么对于之后的度量处理程序来说,有价值的信息就会丢失。我说的WebMvcTagsProvider是特别,但我想这适用于各种用例。

由于有线程池,一个线程最终会被重用,并包含来自之前 HTTP 请求的 MDC 上下文,这很糟糕!

那么如何在 setup 和 finalize 方法中“包装”线程的使用呢?理想情况下,这将是一个通用解决方案。我不想更改现有代码。目标是,新的传入请求无法访问以前的 MDC 上下文。

我已经知道如何在 Java EE 世界中解决这个问题,例如:

@Provider
@Priority(Priorities.USER + 1)
public class MdcClearFilter implements ContainerResponseFilter {
    @Override
    public void filter(
        ContainerRequestContext requestContext,
        ContainerResponseContext responseContext) {
        MDC.clear();
    }
}

那么我如何在 Spring Boot 世界中做同样的事情呢?

标签: javaspring-bootspring-boot-actuator

解决方案


由于HandlerInterceptors 都在 Servlet 上下文中,因此它们无法突破。

所以解决方案是使用Filter带有 order的 servlet Ordered.HIGHEST_PRECEDENCE

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MDCClearFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, 
                         ServletResponse response, 
                         FilterChain chain)
            throws IOException, ServletException {

        chain.doFilter(request, response);
        MDC.clear();
    }
}

推荐阅读