概述:
1、实现拦截器,请求开始时候创建MDC值,结束后清理MDC值
2、实现线程池,将MDC上下文从主线程传递给子线程
具体实现:
1、拦截器请求的进来和结束的时候设置hash值:
import org.jetbrains.annotations.NotNull; import org.slf4j.MDC; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.UUID; /** * 拦截器 * * @author 许伟强51189 * @date 2022/5/25 10:41 */ public class TraceIdInterceptor implements HandlerInterceptor { public static final String UNIQUE_ID = "TRACE_ID"; public boolean preHandle(@NotNull HttpServletRequest httpServletRequest, @NotNull HttpServletResponse httpServletResponse, @NotNull Object o) { MDC.put(UNIQUE_ID, UUID.randomUUID().toString()); return true; } public void postHandle(@NotNull HttpServletRequest httpServletRequest, @NotNull HttpServletResponse httpServletResponse, @NotNull Object o, ModelAndView modelAndView) { } public void afterCompletion(@NotNull HttpServletRequest httpServletRequest, @NotNull HttpServletResponse httpServletResponse, @NotNull Object o, Exception e) { MDC.clear(); } }
2、注册拦截器:
import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * TraceID的拦截器\生成請求的唯一值 * * @author 许伟强51189 * @date 2022/5/25 10:41 */ @Configuration public class TraceIdInterceptorConfiguration implements WebMvcConfigurer { @Value("${spring.traceIdInterceptor.enable:false}") private Boolean enable; @Value("${spring.traceIdInterceptor.addPathPatterns:/**}") private String[] addPathPatterns; @Value("${spring.traceIdInterceptor.excludePathPatterns:}") private String[] excludePathPatterns; @Override public void addInterceptors(@NotNull InterceptorRegistry interceptorRegistry) { if (!enable) { return; } TraceIdInterceptor myInterceptor = new TraceIdInterceptor(); interceptorRegistry.addInterceptor(myInterceptor).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns); } }
3、实现线程池,用于解决异步线程时候 @Async("name") 的 traceId 丢失问题
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; /** * MdcThreadPoolConfiguration - 用于链路追踪MDC的线程池\在多线程情况下会将主线程的上下文传递给子线程 * * @author 许伟强51189 * @date 2022/5/25 16:50 */ @EnableAsync @Configuration public class MdcThreadPoolConfiguration { private int corePoolSize = 50; private int maxPoolSize = 200; private int queueCapacity = 1000; private int keepAliveSeconds = 300; @Bean(name = "threadPoolTaskExecutor") public ThreadPoolTaskExecutor threadPoolTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setMaxPoolSize(maxPoolSize); executor.setCorePoolSize(corePoolSize); executor.setQueueCapacity(queueCapacity); executor.setKeepAliveSeconds(keepAliveSeconds); executor.setTaskDecorator(new MdcTaskDecorator()); // 线程池对拒绝任务(无线程可用)的处理策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } }
4、线程池上下文传递
/** * 任务适配器 * * @author 许伟强51189 * @version 2.0.0 * @date 2022/5/25 15:36 */ public class MdcTaskDecorator implements TaskDecorator { /** * 使异步线程池获得主线程的上下文 * * @param runnable * @return */ @Override public Runnable decorate(Runnable runnable) { Map<String, String> map = MDC.getCopyOfContextMap(); return () -> { try { MDC.setContextMap(map); runnable.run(); } finally { MDC.clear(); } }; } }
5、验证可用(当指定线程池 threadPoolTaskExecutor 的时候 MDC 的值不会丢失,不指定的时候会丢失):
@Async("threadPoolTaskExecutor") public void getUserListAsyncThree(int page, int limit, String hash) { log.info("getUserListAsyncThree Thread Name:{}", Thread.currentThread().getName()); System.out.println(MDC.get(TraceIdInterceptor.UNIQUE_ID)); }
如果使用同一个线程池则可以获取到MDC的值否则不可以
参考博客:
https://jishuin.proginn.com/p/763bfbd69eeb