配置启用MDC日志的Apache Camel路由时MDC值丢失问题
Apache Camel路由中MDC日志丢失问题解决
问题原因
你的路由中使用了multicast().parallelProcessing(),该配置会开启新线程并行处理消息。由于MDC(Mapped Diagnostic Context)基于**线程本地存储(ThreadLocal)**实现,线程切换后原线程的MDC上下文无法自动传递到新线程,导致日志中无法获取到MDC值。
解决方案
1. 禁用并行处理(业务允许情况下)
如果业务逻辑不需要并行执行,直接移除.parallelProcessing()配置,让multicast在原线程执行,MDC上下文会自然保留:
.when(header("type").isEqualTo("DealInvitationEvent")) .multicast() // 去掉.parallelProcessing() .process(invitationEventProcessor) .end()
2. 配置MDC感知的线程池
利用Camel提供的MDCThreadPoolFactory,让并行线程继承原线程的MDC上下文:
步骤1:定义MDC感知的线程池Bean
import org.apache.camel.util.concurrent.MDCThreadPoolFactory; import org.apache.camel.util.concurrent.DefaultThreadFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @Bean public ExecutorService multicastMdcExecutor() { return new ThreadPoolExecutor( 5, // 核心线程数 10, // 最大线程数 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new MDCThreadPoolFactory(new DefaultThreadFactory("multicast-mdc-pool")) ); }
步骤2:路由中指定该线程池
.when(header("type").isEqualTo("DealInvitationEvent")) .multicast(multicastMdcExecutor()) // 传入自定义线程池 .parallelProcessing() .process(invitationEventProcessor) .end()
3. 手动传递MDC上下文(无侵入线程池配置)
如果不想修改线程池,可以通过Exchange属性手动传递MDC:
步骤1:在前置Processor中保存MDC到Exchange
在outboxHeaderEnricherProcessor中添加代码,将当前MDC上下文存入Exchange属性:
import org.slf4j.MDC; import java.util.Map; public void process(Exchange exchange) throws Exception { // 保存当前MDC上下文到Exchange属性 Map<String, String> mdcContext = MDC.getCopyOfContextMap(); exchange.setProperty("MDC_CONTEXT", mdcContext); // 原有业务逻辑... }
步骤2:在并行Processor中恢复MDC
在每个并行处理的Processor(如invitationEventProcessor、enquiryAcceptedEventProcessor等)开头添加恢复逻辑:
import org.slf4j.MDC; import java.util.Map; public void process(Exchange exchange) throws Exception { // 从Exchange属性中取出MDC上下文并恢复 Map<String, String> mdcContext = exchange.getProperty("MDC_CONTEXT", Map.class); if (mdcContext != null) { MDC.setContextMap(mdcContext); } // 原有业务逻辑... // 可选:处理完成后清除当前线程MDC,避免线程复用导致上下文污染 // MDC.clear(); }
额外检查点
- 确认
application.yml中的MDC配置已生效:启动日志中搜索MDCLogging,应能看到“Enabled MDC logging”相关输出。 - 调用
producerTemplate前,确保MDC值已正确设置(比如在调用方代码中MDC.put("key", "value"))。
内容的提问来源于stack exchange,提问作者Mayuran
相关产品推荐
相关产品推荐

