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

Java集成Brave/Zipkin初始化首条链路时currentSpan为空NPE问题求助

问题根因
  • tracer.currentSpan() 的作用是获取当前线程上下文中已经激活的Span实例,你当前的应用作为链路首节点,程序启动后从未主动创建过任何Span,因此该方法返回null,调用span.context()自然触发空指针异常。
正确实现方案

作为链路首节点,你需要主动创建根Span,再基于该Span的上下文传递链路信息,完整的修正代码如下:

import io.netty.handler.logging.LogLevel;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
import zipkin2.reporter.AsyncReporter;
import zipkin2.reporter.brave.ZipkinSpanHandler;
import zipkin2.reporter.urlconnection.URLConnectionSender;
import brave.Tracing;
import brave.Tracer;
import brave.Span;
import brave.propagation.B3Propagation;
import brave.propagation.Propagation;
import brave.propagation.TraceContext;
import java.util.Map;

public class QuestionApplication {

    private static final Propagation<String> B3_PROPAGATION = B3Propagation.newFactoryBuilder().build().get();
    private static final TraceContext.Injector<WebClient.Builder> INJECTOR = B3_PROPAGATION.injector((builder, key, value) -> {
        builder.defaultHeader(key, value);
    });

    public static void main(String[] args) {
        final var sender = URLConnectionSender.create("http://the-zipkin-instance.com:9411/api/v2/spans");
        final var spanReporter = AsyncReporter.create(sender);
        final var tracing = Tracing.newBuilder()
                .localServiceName("thisIsTheClientApplicationWhoIsGeneratingTheFirstTraceId")
                .addSpanHandler(ZipkinSpanHandler.create(spanReporter))
                .propagationFactory(B3Propagation.FACTORY)
                .build();
        final Tracer tracer = tracing.tracer();
        
        // 主动创建根Span(链路首节点)
        Span rootSpan = tracer.nextSpan().name("client-call-server").start();
        try (Tracer.SpanInScope ignored = tracer.withSpanInScope(rootSpan)) {
            final var webClientBuilder = WebClient.builder()
                    .clientConnector(new ReactorClientHttpConnector(HttpClient.create()
                            .wiretap("reactor.netty.http.client.HttpClient", LogLevel.INFO, AdvancedByteBufFormat.HEX_DUMP)));
            // 自动注入所有B3链路头(不需要手动拼X-B3-TraceId等字段)
            INJECTOR.inject(rootSpan.context(), webClientBuilder);
            WebClient webClient = webClientBuilder.build();
            
            final var jsonPayload = Map.of("key", "someKey", "value", "someValue");
            final var response = webClient.post()
                    .uri("http://the-server.com/api/route")
                    .body(BodyInserters.fromValue(jsonPayload))
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();
            System.out.println(response);
        } finally {
            // 必须结束Span,否则追踪数据不会上报
            rootSpan.finish();
            // 同步刷盘,避免JVM退出前异步Reporter还没发数据
            spanReporter.flush();
            tracing.close();
        }
    }
}
关键注意点
  • 根Span必须通过tracer.nextSpan()主动创建,无父节点的Span会自动生成全新的Trace ID
  • 不要手动拼接X-B3系列请求头,使用Brave提供的Propagation注入能力,会自动补全TraceId、SpanId、Sampled等所有标准链路头,避免传递漏项
  • Span使用完成后必须调用finish()方法,否则追踪数据不会被上报到Zipkin
  • 应用退出前需要手动调用AsyncReporter的flush()方法,避免内存中缓存的未上报链路数据丢失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 01:09:04