在 Spring Boot 3.x 项目中,如果你想将主线程中的 MDC(Mapped Diagnostic Context)数据传递到 ThreadPoolTaskExecutor
管理的子线程中,可以使用 TaskDecorator
接口。
TaskDecorator
允许你在每个任务被执行之前进行一些处理,例如将 MDC 数据从主线程复制到子线程。以下是一个实现示例:
1. 定义一个 MDC 传递的 TaskDecorator
import org.slf4j.MDC;
import org.springframework.core.task.TaskDecorator;
import java.util.Map;
public class MdcTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// Capture the context of the current thread (the main thread)
Map<String, String> contextMap = MDC.getCopyOfContextMap();
return () -> {
try {
// Set the context map for the child thread
if (contextMap != null) {
MDC.setContextMap(contextMap);
}
runnable.run();
} finally {
// Clear the context map after the child thread has finished
MDC.clear();
}
};
}
}
2. 配置 ThreadPoolTaskExecutor
并使用 TaskDecorator
在你的 Spring 配置类中,配置 ThreadPoolTaskExecutor
并设置 TaskDecorator
:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
public class ThreadPoolConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("MyExecutor-");
// Set the TaskDecorator
executor.setTaskDecorator(new MdcTaskDecorator());
executor.initialize();
return executor;
}
}
3. 在主线程中设置 MDC 并使用 ThreadPoolTaskExecutor
在主线程中,可以像平常一样使用 MDC,然后提交任务到线程池:
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
public void executeTask() {
// Set some MDC context in the main thread
MDC.put("traceId", "12345");
// Submit task to the thread pool
taskExecutor.execute(() -> {
// The MDC context is now available here
System.out.println("Trace ID: " + MDC.get("traceId"));
});
// Clear MDC context after task submission if necessary
MDC.clear();
}
}
4. 结果
在这个配置中,主线程中的 MDC 数据会被传递到由 ThreadPoolTaskExecutor
管理的子线程中,从而在子线程中也可以访问到相同的 MDC 数据。
这种方式确保了在异步任务执行时,日志上下文(如 traceId
或 requestId
等)能够贯穿整个请求链路。