MDC 的底层是 ThreadLocal,线程池复用线程,上下文不会自己跟过去。
提交任务前先把 MDC 的内容取出来,在子线程里 set 回去。
用 TaskDecorator 装饰线程池,包一层就能全局生效,不用改业务代码。
记得在 finally 里 clear,线程池复用时不清理会把脏数据带给下个任务。
// 1) 最简单:手动透传
Map<String, String> ctx = MDC.getCopyOfContextMap();
executor.submit(() -> {
if (ctx != null) MDC.setContextMap(ctx);
try { doWork(); } finally { MDC.clear(); } // 必须清,线程会复用
});
// 2) 推荐:TaskDecorator 装饰线程池,全局生效
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
ex.setCorePoolSize(8);
ex.setTaskDecorator(runnable -> {
Map<String, String> c = MDC.getCopyOfContextMap();
return () -> {
if (c != null) MDC.setContextMap(c);
try { runnable.run(); } finally { MDC.clear(); }
};
});
ex.initialize();
return ex;
}
// 注意:@Async 要指定这个执行器(@Async("taskExecutor"))。
// CompletableFuture.supplyAsync 默认走 ForkJoinPool,不会用这个装饰器。
THE END






暂无评论内容