springboot3.2发布了,配合jdk21使用虚拟线程,使用MDC + traceId追踪日志方法
关于虚拟线程和MDC traceId这里就不多说了,如果不清楚请自行查询资料
第一步,创建MdcVirtualThreadTaskExecutor
/** * @author xxley * @date 2022/7/25 15:54 */ public class MdcVirtualThreadTaskExecutor extends TaskExecutorAdapter { public MdcVirtualThreadTaskExecutor(Executor concurrentExecutor) { super(concurrentExecutor); } @Override public <T> Future<T> submit(Callable<T> callable) { Map<String, String> context = MDC.getCopyOfContextMap(); return super.submit(() -> { if (context != null) { //将父线程的MDC内容传给子线程 MDC.setContextMap(context); } else { //直接给子线程设置MDC // 这个方法是我自己封装的,实际是MDC.put("traceId", traceId); TraceIdContext.setMCData(null); } try { //执行任务 return callable.call(); } finally { MDC.clear(); } }); } @Override public void execute(Runnable runnable) { Map<String, String> context = MDC.getCopyOfContextMap(); super.execute(() -> { if (context != null) { //将父线程的MDC内容传给子线程 MDC.setContextMap(context); } else { //直接给子线程设置MDC // 这个方法是我自己封装的,实际是MDC.put("traceId", traceId); TraceIdContext.setMCData(null); } try { //执行任务 runnable.run(); } finally { MDC.clear(); } }); } }
第二步,配置AsyncConfig
@Configuration @EnableAsync public class AsyncConfig { @Bean public TaskExecutor taskExecutor(SimpleAsyncTaskExecutorBuilder executor) { SimpleAsyncTaskExecutor build = executor.build(); return new MdcVirtualThreadTaskExecutor(build); } }
此时使用@Async异步调用, 在异步方法中输出的日志就会携带主线程的traceId
虚拟线程不要池化,创建和销毁虚拟线程消耗资源很低,可以忽略不计。
这是我找到的一种方法,如果你有更好的方法,请告知一下。