Java-12a.Spring 中通过 TaskDecorator 配置默认异步线程池
前言
虽然在 SpringBoot 2.7.x 中已经有关于异步线程池的默认配置,但如果还是要自定义的需求,仍然值得学习了解一下。
例如:想要在多线程池中添加 traceId;使用 transmittable-thread-local
来代替默认的 ThreadLocal
。
多线程日志追踪工具类
MdcUtil
public class MdcUtil {
public static final String TRACE_ID = "traceId";
public static String generateTraceId() {
return UUID.randomUUID().toString().replace("-", "");
}
public static String getTraceId() {
return MDC.get(TRACE_ID);
}
public static void setTraceId(String traceId) {
MDC.put(TRACE_ID, traceId);
}
public static void setContextMap(Map<String, String> context) {
MDC.setContextMap(context);
}
public static void removeTraceId() {
MDC.remove(TRACE_ID);
}
public static void clear() {
MDC.clear();
}
}
ThreadMdcUtil
public class ThreadMdcUtil {
public static void setTraceIdIfAbsent() {
if (MdcUtil.getTraceId() == null) {
MdcUtil.setTraceId(MdcUtil.generateTraceId());
}
}
public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
return () -> {
if (context == null) {
MdcUtil.clear();
} else {
MdcUtil.setContextMap(context);
}
setTraceIdIfAbsent();
try {
return callable.call();
} finally {
MdcUtil.clear();
}
};
}
public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
return () -> {
if (context == null) {
MdcUtil.clear();
} else {
MdcUtil.setContextMap(context);
}
//设置traceId
setTraceIdIfAbsent();
try {
runnable.run();
} finally {
MdcUtil.clear();
}
};
}
}
自定义 ThreadPoolTaskExecutor
/**
* 日志追踪线程池配置
*
* @author fengxc
*/
public class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
@Override
public void execute(@NotNull Runnable task) {
super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@NotNull
@Override
public Future<?> submit(@NotNull Runnable task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
@NotNull
@Override
public <T> Future<T> submit(@NotNull Callable<T> task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
}
继承 AsyncConfigurerSupport 实现默认的异步线程池
@EnableAsync
@SpringBootConfiguration
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class ThreadPoolConfig extends AsyncConfigurerSupport {
@Resource
private TaskExecutionProperties properties;
/**
* 重写默认线程池配置,@Async异步会使用这个线程池
*/
@Override
public Executor getAsyncExecutor() {
TaskExecutionProperties.Pool pool = properties.getPool();
TaskExecutorBuilder builder = new TaskExecutorBuilder();
builder = builder.queueCapacity(pool.getQueueCapacity());
builder = builder.corePoolSize(pool.getCoreSize());
builder = builder.maxPoolSize(pool.getMaxSize());
builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
builder = builder.keepAlive(pool.getKeepAlive());
Shutdown shutdown = properties.getShutdown();
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
CustomThreadPoolTaskExecutor executor = builder.build(CustomThreadPoolTaskExecutor.class);
executor.initialize();
return TtlExecutors.getTtlExecutor(executor);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}