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
虚拟线程不要池化,创建和销毁虚拟线程消耗资源很低,可以忽略不计。
这是我找到的一种方法,如果你有更好的方法,请告知一下。