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

Spring Boot微服务:如何将请求头参数设为Log4j查找变量?

实现方案:用MDC+Log4j2自动注入track_number到日志

完全可以实现,不用在每个方法里手动传递参数,核心是借助MDC(映射诊断上下文)——这是Log4j等日志框架专门用于存储请求级上下文数据的机制,具体步骤如下:

1. 在请求入口将track_number存入MDC

用Spring的请求拦截器,在请求进入Controller前把track_number放入MDC,请求结束后清除(避免ThreadLocal内存泄漏):

1.1 编写拦截器

import org.slf4j.MDC;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TrackNumberInterceptor implements HandlerInterceptor {
    private static final String TRACK_NUMBER_KEY = "track_number";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从请求头获取track_number,无值时设默认值
        String trackNumber = request.getHeader(TRACK_NUMBER_KEY);
        MDC.put(TRACK_NUMBER_KEY, trackNumber != null ? trackNumber : "unknown");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求结束后清除MDC中的值,防止线程复用导致数据污染
        MDC.remove(TRACK_NUMBER_KEY);
    }
}

1.2 注册拦截器

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TrackNumberInterceptor())
                // 拦截所有请求,可根据实际业务调整路径
                .addPathPatterns("/**");
    }
}

2. 修改Log4j2.xml配置,在日志格式中引用MDC的track_number

修改日志输出模板,加入%X{track_number}(%X是Log4j2引用MDC变量的语法),示例配置:

<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <!-- 格式中加入track_number,无值时显示unknown -->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %X{track_number:-unknown} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

3. 业务代码中正常打日志即可

不管是Controller、Service还是Repo层,直接用Lombok的@Slf4j注解打日志,不需要额外传递track_number:

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class DemoService {
    public void doBusinessLogic() {
        // 日志会自动带上当前请求的track_number
        log.info("开始执行核心业务逻辑");
        log.debug("调试信息:当前请求追踪号已自动注入");
    }
}

注意事项:异步线程的上下文传递

如果服务使用了@Async异步方法,由于MDC基于ThreadLocal实现,异步线程会丢失上下文,需要手动传递:

  1. 自定义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) {
        // 捕获当前线程的MDC上下文
        Map<String, String> mdcContext = MDC.getCopyOfContextMap();
        return () -> {
            try {
                // 将MDC上下文设置到异步线程中
                if (mdcContext != null) {
                    MDC.setContextMap(mdcContext);
                }
                runnable.run();
            } finally {
                // 清除异步线程的MDC
                MDC.clear();
            }
        };
    }
}
  1. 配置线程池时绑定Decorator:
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 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(20);
        executor.setThreadNamePrefix("AsyncThread-");
        // 绑定MDC装饰器,传递上下文
        executor.setTaskDecorator(new MdcTaskDecorator());
        executor.initialize();
        return executor;
    }
}

配置后,异步方法的日志也能正常带上track_number。

内容的提问来源于stack exchange,提问作者Jishnu Prathap

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 17:40:21