前置说明在微服务链路追踪中同步 HTTP、OpenFeign、RestTemplate 调用仅引入链路依赖就能自动透传traceId/spanId但Async异步方法、自定义线程池、定时任务、MQ跨进程通信会发生线程切换ThreadLocal 上下文丢失链路直接断裂。本文将详细讲解对应的解决方案。一、Spring Boot2 Sleuth 方案场景1使用Spring默认全局Async线程池未自定义Executor BeanSleuth内置后置处理器ExecutorBeanPostProcessor会自动拦截容器内ThreadPoolTaskExecutor并包装链路上下文无需手动编码、无需新增依赖直接使用即可自动传递traceId。场景2自定义ThreadPoolTaskExecutorBean声明不能依靠自动代理必须手动包装线程池任务两种写法任选其一写法1包装线程池推荐全局统一配置importbrave.Tracer;importbrave.spring.beans.TraceableExecutorService;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importjavax.annotation.Resource;importjava.util.concurrent.Executor;importjava.util.concurrent.ThreadPoolExecutor;ConfigurationpublicclassAsyncPoolConfig{ResourceprivateTracertracer;BeanpublicExecutorasyncExecutor(){ThreadPoolTaskExecutorexecutornewThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(200);executor.setThreadNamePrefix(async-task-);executor.initialize();// Sleuth专属包装类绑定链路上下文returnnewTraceableExecutorService(tracer,executor.getThreadPoolExecutor());}}写法2单个Runnable手动包装零散临时线程// 原始异步任务Runnabletask()-{// 业务逻辑};// 手动绑定当前链路上下文RunnabletraceTaskTraceableExecutorService.wrap(tracer,task);executor.submit(traceTask);场景3new ThreadPoolExecutor 原生线程池不归Spring容器管理Spring无法感知该线程池自动代理失效必须逐个包装提交的任务。场景4Scheduled 定时任务定时任务使用独立调度线程默认丢失上下文解决方案少量定时任务方法内手动捕获上下文再执行全局定时任务池参照场景2给ScheduledExecutor用TraceableExecutorService包装。场景5RocketMQ/Kafka 消息队列跨进程生产者、消费者分属两个独立应用线程上下文天然隔离任何线程池包装都无效生产者拦截器发送消息时把traceId、spanId写入消息自定义Header消费者拦截器消费消息时从Header取出链路ID重建Trace上下文该场景无法靠依赖自动处理必须自定义拦截器。二、Spring Boot3 Micrometer Tracing该版本无自动代理线程池的内置逻辑所有异步场景都需要手动处理上下文快照。核心APIContextSnapshot上下文快照实现主线程上下文拷贝到子线程场景1全局统一Async线程池配置一次配置全局生效最常用importio.micrometer.context.ContextSnapshot;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.annotation.EnableAsync;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importorg.springframework.core.task.TaskDecorator;importjava.util.concurrent.Executor;EnableAsyncConfigurationpublicclassAsyncTraceConfig{Bean(traceAsyncExecutor)publicExecutortraceAsyncExecutor(){ThreadPoolTaskExecutorexecutornewThreadPoolTaskExecutor();executor.setCorePoolSize(4);executor.setMaxPoolSize(8);// 任务装饰器每次提交任务自动拷贝链路上下文TaskDecoratordecoratorrunnable-()-{// 捕获当前主线程全部上下文ContextSnapshotsnapshotContextSnapshot.captureAll();try(ContextSnapshot.Scopescopesnapshot.setThreadLocals()){runnable.run();}};executor.setTaskDecorator(decorator);executor.initialize();returnexecutor;}}使用时指定线程池Async(traceAsyncExecutor)所有异步方法自动续上链路。场景2零散临时Runnable、手动提交任务Autowiredprivateio.micrometer.tracing.Tracertracer;publicvoidsubmitTask(){RunnablebizTask()-{// 异步业务代码};// 手动包装上下文ContextSnapshotsnapshotContextSnapshot.captureAll();RunnablewrappedTask()-{try(ContextSnapshot.Scopescopesnapshot.setThreadLocals()){bizTask.run();}};executor.submit(wrappedTask);}场景3Scheduled 定时任务改造定时任务调度线程池同样配置上面的TaskDecorator装饰器快照传递上下文。场景4MQ跨进程收发Spring官方MQ客户端KafkaTemplate、RabbitTemplate已原生适配W3C标准traceparent请求头发送时自动写入Header消费端自动解析恢复上下文无需手写拦截器自定义原生MQ生产者工具类依旧需要手动读写消息Header传递traceId。