You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java Spring @Async线程中记录TRACE-ID

解决Spring异步方法传递MDC上下文(TRACE-ID)的问题

问题根源

Spring的@Async默认线程池不会复制父线程的MDC(映射诊断上下文)内容,导致异步线程无法获取父请求中的TRACE-ID和X-CLIENT-ID,日志中对应字段为空。

解决方案

方法一:自定义异步线程池自动传递MDC

创建配置类,重写线程池的任务提交逻辑,将父线程的MDC上下文复制到异步线程:

import org.slf4j.MDC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Map;
import java.util.concurrent.Executor;

@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("CustomAsync-");
        executor.initialize();
        
        // 包装线程池,传递MDC上下文
        return runnable -> {
            Map<String, String> mdcContext = MDC.getCopyOfContextMap();
            executor.execute(() -> {
                try {
                    if (mdcContext != null) {
                        MDC.setContextMap(mdcContext);
                    }
                    runnable.run();
                } finally {
                    MDC.clear();
                }
            });
        };
    }
}

方法二:手动传递上下文(单方法场景)

针对特定异步方法,手动将父线程MDC上下文作为参数传入,再在异步方法中设置:

  1. 调用方代码:
@Service
public class ParentService {
    private final SculptService sculptService;

    public ParentService(SculptService sculptService) {
        this.sculptService = sculptService;
    }

    public void handleRequest() {
        // 获取当前MDC上下文
        Map<String, String> mdcContext = MDC.getCopyOfContextMap();
        // 传入异步方法
        sculptService.asyncMethod(mdcContext);
    }
}
  1. 异步方法类:
@Service
public class SculptService {

    @Async
    public void asyncMethod(Map<String, String> mdcContext) {
        try {
            if (mdcContext != null) {
                MDC.setContextMap(mdcContext);
            }
            // 执行异步逻辑,日志将输出父请求的TRACE-ID
            log.info("Some log...");
        } finally {
            MDC.clear();
        }
    }
}

方法三:使用Spring内置MdcTaskDecorator(Spring 4.3+)

利用Spring提供的MdcTaskDecorator简化配置,自动传递MDC:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.task.support.MdcTaskDecorator;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean(name = "asyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("MdcAsync-");
        // 添加MDC装饰器
        executor.setTaskDecorator(new MdcTaskDecorator());
        executor.initialize();
        return executor;
    }
}

在异步方法上指定使用该线程池:

@Async("asyncExecutor")
public void asyncMethod() {
    log.info("Some log...");
}

验证效果

配置完成后,异步方法日志将显示父请求的TRACE-ID和X-CLIENT-ID,示例:

2022-11-18 15:23:32,123 [MdcAsync-1] TRACE-ID=[dcb803cb074a4e71ab4f9f43aa3c2ca1] X-CLIENT-ID=[mfs-reformer] INFO a.a.m.r.s.SculptService#55 - Some log...

内容的提问来源于stack exchange,提问作者Rakesh Malik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 01:55:23