异步线程获取上下文的MDC信息
异步线程traceId如何传递_new thread子线程传递traceid-CSDN博客
1. 重写线程池,来实现自定义线程池
a.下面的工具类,分别在Callable和Runnable异步任务执行前通过MDC.setContextMap(context)设置请求映射上下文
1 import org.slf4j.MDC; 2 import org.springframework.util.CollectionUtils; 3 4 import java.util.Map; 5 import java.util.concurrent.Callable; 6 7 /** 8 * @desc: 定义MDC工具类,支持Runnable和Callable两种,目的就是为了把父线程的traceId设置给子线程 9 */ 10 public class MdcUtil { 11 12 public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) { 13 return () -> { 14 if (CollectionUtils.isEmpty(context)) { 15 MDC.clear(); 16 } else { 17 MDC.setContextMap(context); 18 } 19 try { 20 return callable.call(); 21 } finally { 22 // 清除子线程的,避免内存溢出,就和ThreadLocal.remove()一个原因 23 MDC.clear(); 24 } 25 }; 26 } 27 28 public static Runnable wrap(final Runnable runnable, final Map<String, String> context) { 29 return () -> { 30 if (CollectionUtils.isEmpty(context)) { 31 MDC.clear(); 32 } else { 33 MDC.setContextMap(context); 34 } 35 try { 36 runnable.run(); 37 } finally { 38 MDC.clear(); 39 } 40 }; 41 } 42 }
b.下面定义一个ThreadPoolMdcExecutor 类来继承ThreadPoolTaskExecutor 类,重写execute和submit方法
1 import java.util.concurrent.Callable; 2 import java.util.concurrent.Future; 3 4 /** 5 * @desc: 把当前的traceId透传到子线程特意加的实现。 6 * 重点就是 MDC.getCopyOfContextMap(),此方法获取当前线程(父线程)的traceId 7 */ 8 public class ThreadPoolMdcExecutor extends ThreadPoolTaskExecutor { 9 @Override 10 public void execute(Runnable task) { 11 super.execute(MdcUtil.wrap(task, MDC.getCopyOfContextMap())); 12 } 13 14 @Override 15 public Future<?> submit(Runnable task) { 16 return super.submit(MdcUtil.wrap(task, MDC.getCopyOfContextMap())); 17 } 18 19 @Override 20 public <T> Future<T> submit(Callable<T> task) { 21 return super.submit(MdcUtil.wrap(task, MDC.getCopyOfContextMap())); 22 } 23 }
c.创建线程池Bean
1 @Bean(name = "callBackExecutorConfig") 2 public Executor callBackExecutorConfig() { 3 ThreadPoolTaskExecutor executor = new ThreadPoolMdcExecutor(); 4 // 配置核心线程数 5 executor.setCorePoolSize(10); 6 // 配置最大线程数 7 executor.setMaxPoolSize(20); 8 // 配置队列大小 9 executor.setQueueCapacity(200); 10 // 配置线程池中的线程的名称前缀 11 executor.setThreadNamePrefix("async-Thread-"); 12 // rejection-policy:当pool已经达到max size的时候,如何处理新任务 13 // abort:在调用executor执行的方法中抛出异常 RejectedExecutionException 14 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); 15 // 执行初始化 16 executor.initialize(); 17 return executor; 18 }
2.对默认线程池进行增强
a.通过实现TaskDecorator 接口来增强线程池
1 public class ContextTransferTaskDecorator implements TaskDecorator { 2 @Override 3 public Runnable decorate(Runnable runnable) { 4 Map<String, String> context = MDC.getCopyOfContextMap(); 5 6 // //子线程调用RequestContextHolder.currentRequestAttributes()会throw new IllegalStateException 7 // //需要在执行子线程之前,在主线程中设置属性子线程共享 8 // //ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 9 // //RequestContextHolder.setRequestAttributes(servletRequestAttributes,true); 10 // RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); 11 return () -> { 12 try { 13 MDC.setContextMap(context); 14 // RequestContextHolder.setRequestAttributes(requestAttributes); 15 runnable.run(); 16 } finally { 17 //防止线程内部MDC的内存泄漏,此处清除的是线程内部的MDC不影响主线程MDC信息 18 MDC.clear(); 19 // RequestContextHolder.resetRequestAttributes(); 20 } 21 }; 22 } 23 }
2.默认线程池的ThreadPoolTaskExecutor.setTaskDecorator
1 @Bean(name = "callBackExecutorConfig") 2 public Executor callBackExecutorConfig() { 3 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor (); 4 // 配置核心线程数 5 executor.setCorePoolSize(10); 6 // 配置最大线程数 7 executor.setMaxPoolSize(20); 8 // 配置队列大小 9 executor.setQueueCapacity(200); 10 // 配置线程池中的线程的名称前缀 11 executor.setThreadNamePrefix("async-Thread-"); 12 // rejection-policy:当pool已经达到max size的时候,如何处理新任务 13 // abort:在调用executor执行的方法中抛出异常 RejectedExecutionException 14 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); 15 //线程池增强 16 threadPoolTaskExecutor.setTaskDecorator(new ContextTransferTaskDecorator()); 17 // 执行初始化 18 executor.initialize(); 19 return executor; 20 }