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

SpringBoot Reactive(WebClient):TraceId无法传递到Reactor线程?

响应式WebFlux中Micrometer追踪上下文丢失问题

问题场景

基于Spring Boot 3.x开发的应用,使用Spring WebFlux和响应式WebClient,通过Micrometer实现链路追踪。命令式Servlet栈中追踪功能正常,但切换到Project Reactor线程时,TraceId、SpanId等追踪上下文丢失,日志中对应字段为空。

现有配置

Reactor上下文传播配置

spring.reactor.context-propagation=auto

Logback日志格式

%d %-5level %-50.50logger{50} [%thread,%X{traceId:-},%X{spanId:-}] %msg%n

日志输出示例

2025-09-14 15:59:20,064 TRACE o.s.web.reactive.function.client.ExchangeFunctions [http-nio-8080-exec-1,68c6ca3839216185f4ca70c9a8ee1823,a98bd42951d46230] [774c1457] HTTP GET https://httpbin.org/get, headers={masked}
2025-09-14 15:59:20,164 TRACE o.s.web.reactive.function.client.WebClient         [reactor-http-epoll-3,,] [9660dd0c] REGISTERED
2025-09-14 15:59:20,200 TRACE o.s.web.reactive.function.client.WebClient         [reactor-http-epoll-3,,] [9660dd0c] CONNECT: httpbin.org/34.238.12.187:443
2025-09-14 15:59:20,335 TRACE o.s.web.reactive.function.client.WebClient         [reactor-http-epoll-3,,] [9660dd0c, L:/172.16.44.117:57450 - R:httpbin.org/34.238.12.187:443] ACTIVE
2025-09-14 15:59:20,435 TRACE o.s.web.reactive.function.client.WebClient         [reactor-http-epoll-3,,] [9660dd0c, L:/172.16.44.117:57450 - R:httpbin.org/34.238.12.187:443] READ COMPLETE
2025-09-14 15:59:20,458 TRACE o.s.web.reactive.function.client.WebClient         [reactor-http-epoll-3,,] [9660dd0c, L:/172.16.44.117:57450 - R:httpbin.org/34.238.12.187:443] READ COMPLETE
2025-09-14 15:59:20,571 TRACE o.s.web.reactive.function.client.WebClient         [reactor-http-epoll-3,,] [9660dd0c-1, L:/172.16.44.117:57450 - R:httpbin.org/34.238.12.187:443] WRITE: 155B GET /get HTTP/1.1

可见切换到reactor-http-epoll-3线程后,TraceId和SpanId字段为空。

环境信息

  • Spring Boot: 3.x
  • Spring WebFlux: 响应式栈
  • Micrometer Tracing
  • 日志框架: Logback + MDC

解决方案

1. 确保上下文传播依赖完整

Spring Boot 3.x中,Micrometer Tracing的上下文传播需要依赖reactor-core的上下文传播能力,确保引入正确的依赖:

<!-- Maven依赖示例 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-core</artifactId>
    <version>3.5.x</version> <!-- 与Spring Boot 3.x兼容版本 -->
</dependency>

2. 显式配置追踪上下文传播

尽管spring.reactor.context-propagation=auto会自动配置,但显式注册Micrometer的上下文传播器能确保追踪上下文正确传递:

import io.micrometer.tracing.Tracer;
import reactor.core.publisher.Hooks;
import reactor.core.publisher.Operators;
import reactor.util.context.Context;
import reactor.util.context.ContextView;

import org.springframework.context.annotation.Configuration;
import jakarta.annotation.PostConstruct;

@Configuration
public class ReactorTracingConfig {

    private final Tracer tracer;

    public ReactorTracingConfig(Tracer tracer) {
        this.tracer = tracer;
    }

    @PostConstruct
    public void setupContextPropagation() {
        Hooks.onEachOperator(Operators.lift((scannable, subscriber) -> new TracingContextSubscriber(subscriber, tracer)));
    }

    private static class TracingContextSubscriber<T> implements reactor.core.CoreSubscriber<T> {
        private final reactor.core.CoreSubscriber<T> delegate;
        private final Tracer tracer;

        public TracingContextSubscriber(reactor.core.CoreSubscriber<T> delegate, Tracer tracer) {
            this.delegate = delegate;
            this.tracer = tracer;
        }

        @Override
        public void onSubscribe(reactor.core.Disposable s) {
            ContextView context = delegate.currentContext();
            Tracer.SpanInScope spanInScope = tracer.withSpan(context.getOrDefault(Tracer.class, tracer).currentSpan());
            delegate.onSubscribe(new reactor.core.Disposable() {
                @Override
                public void dispose() {
                    spanInScope.close();
                    s.dispose();
                }

                @Override
                public boolean isDisposed() {
                    return s.isDisposed();
                }
            });
        }

        @Override
        public void onNext(T t) {
            delegate.onNext(t);
        }

        @Override
        public void onError(Throwable t) {
            delegate.onError(t);
        }

        @Override
        public void onComplete() {
            delegate.onComplete();
        }

        @Override
        public Context currentContext() {
            return delegate.currentContext().put(Tracer.class, tracer);
        }
    }
}

3. 同步MDC与Reactor上下文

响应式环境中MDC不会自动跟随Reactor上下文,需要借助reactor-logback扩展实现同步:

<!-- 引入reactor-logback依赖 -->
<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-logback</artifactId>
    <version>3.5.x</version>
</dependency>

然后注册MDC上下文同步器:

import reactor.core.publisher.Hooks;
import reactor.logback.MdcContextLifter;

import org.springframework.context.annotation.Configuration;
import jakarta.annotation.PostConstruct;

@Configuration
public class ReactorMdcConfig {

    @PostConstruct
    public void setupMdcPropagation() {
        Hooks.onEachOperator(MdcContextLifter.lifter());
    }
}

4. 检查WebClient配置

确保WebClient自动注入了追踪过滤器,若自定义WebClient需手动添加TracingExchangeFilterFunction:

import io.micrometer.tracing.web.reactive.client.TracingExchangeFilterFunction;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient(TracingExchangeFilterFunction tracingFilter) {
        return WebClient.builder()
                .filter(tracingFilter)
                .build();
    }
}

总结

核心需确保两个关键点:

  • 完整的上下文传播依赖与显式配置,保证TraceId/SpanId在Reactor线程间传递
  • 同步MDC与Reactor上下文,让日志框架能正确读取追踪字段

内容的提问来源于stack exchange,提问作者Cyrill Zadra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 08:44:54