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

Spring Boot 3.2.3测试环境BaggageField更新失效问题

问题分析与解决方案

问题概述

我开发了一个链路追踪库,默认会将CorrelationId通过X-MC-Correlation-Id和Correlation-Id请求头传播,同时提供工具类Correlator用于自定义设置CorrelationId以实现全链路追踪。该配置在生产环境运行正常,但在SpringBootTest测试环境中,BaggageField无法正常更新,调用Correlator.setCorrelationId()后获取的值不符合预期。

相关代码

配置类

package com.test.tracing.configuration;

import brave.baggage.BaggageField;
import brave.baggage.BaggagePropagationConfig;
import brave.baggage.BaggagePropagationCustomizer;
import brave.propagation.Propagation;
import com.test.tracing.configuration.EnsureCorrelationIdPropagationFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;


@Configuration
public class CorrelationAutoConfiguration1 {

    public static final BaggageField CORRELATION_ID_BAGGAGE_FIELD = BaggageField.create("correlationId");

    @Bean
    BaggagePropagationCustomizer baggagePropagationCustomizer() {
        return fb -> fb.add(BaggagePropagationConfig.SingleBaggageField
            .newBuilder(CORRELATION_ID_BAGGAGE_FIELD)
            .addKeyName("X-MC-Correlation-Id")
            .addKeyName("Correlation-Id")
            .build());
    }

    @Bean
    static BeanPostProcessor ensureCorrelationIdPropagationFactory() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(@NonNull Object bean, String beanName) {
                if (bean instanceof Propagation.Factory) {
                    return new EnsureCorrelationIdPropagationFactory((Propagation.Factory) bean);
                } else {
                    return bean;
                }
            }
        };
    }

}

传播工厂

package com.test.tracing.configuration;

import brave.propagation.Propagation;
import brave.propagation.TraceContext;
import org.springframework.util.StringUtils;

import java.util.UUID;

import static com.test.tracing.configuration.CorrelationAutoConfiguration.CORRELATION_ID_BAGGAGE_FIELD;

public class EnsureCorrelationIdPropagationFactory extends Propagation.Factory {

    private Propagation.Factory delegate;

    EnsureCorrelationIdPropagationFactory(Propagation.Factory delegate) {
        this.delegate = delegate;
    }

    @Override
    public boolean supportsJoin() {
        return delegate.supportsJoin();
    }

    @Override
    public boolean requires128BitTraceId() {
        return delegate.requires128BitTraceId();
    }

    @Override
    public <K> Propagation<K> create(Propagation.KeyFactory<K> keyFactory) {
        return delegate.create(keyFactory);
    }

    @Override
    public Propagation<String> get() {
        return delegate.get();
    }

    @Override
    public TraceContext decorate(TraceContext context) {
        TraceContext decoratedContext = delegate.decorate(context);
        String correlationId = CORRELATION_ID_BAGGAGE_FIELD.getValue(decoratedContext);
        if (!StringUtils.hasText(correlationId)) {
            CORRELATION_ID_BAGGAGE_FIELD.updateValue(decoratedContext, UUID.randomUUID().toString());
        }
        return decoratedContext;
    }
}

Pom依赖

<properties>
        <aspectjrt-version>1.9.9.1</aspectjrt-version>
        <brave-propagation-aws-version>0.23.4</brave-propagation-aws-version>
        <brave-version>5.14.0</brave-version>
        <zipkin-version>2.23.18</zipkin-version>
        
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing-bridge-brave</artifactId>
            
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectjrt-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-context-slf4j</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-http</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-httpasyncclient</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-httpclient</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-jms</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-kafka-clients</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-kafka-streams</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-messaging</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-mongodb</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-rpc</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-spring-rabbit</artifactId>
            <version>${brave-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.aws</groupId>
            <artifactId>brave-propagation-aws</artifactId>
            <version>${brave-propagation-aws-version}</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.zipkin2</groupId>
            <artifactId>zipkin</artifactId>
            <version>${zipkin-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

工具类

public class Correlator {

    private Correlator() {
    }


    @Nullable
    public static String getCorrelationId() {
        return CorrelationAutoConfiguration.CORRELATION_ID_BAGGAGE_FIELD.getValue();
    }

    
    public static void setCorrelationId(String correlationId) {
        CorrelationAutoConfiguration.CORRELATION_ID_BAGGAGE_FIELD.updateValue(correlationId);
    }
}

测试用例

import com.test.tracing.configuration.CorrelationAutoConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import io.micrometer.tracing.ScopedSpan;
import io.micrometer.tracing.Tracer;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@SpringBootTest(classes = CorrelationAutoConfiguration.class)
@EnableAutoConfiguration
class CorrelatorTest {

    @Autowired
    private Tracer tracer;

    private ScopedSpan span;

    @BeforeEach
    public void setUp() {
        this.span = this.tracer.startScopedSpan("my-scoped-span");
    }

    @AfterEach
    void tearDown() {
        this.span.end();
    }

    @Test
    public void correlationId() {
        String correlationId = "test-5";
        Correlator.setCorrelationId(correlationId);
        assertEquals(correlationId, Correlator.getCorrelationId());
    }

}

问题根源

  1. 类名引用不一致:配置类实际类名为CorrelationAutoConfiguration1,但传播工厂和工具类中引用的是CorrelationAutoConfiguration,导致两者使用的CORRELATION_ID_BAGGAGE_FIELD不是同一个实例。设置操作针对的是一个未被Spring管理的BaggageField实例,而获取操作则是另一个实例,自然无法得到预期值。
  2. 测试上下文关联问题:即使修复了类名问题,测试环境中TraceContext的装饰逻辑可能在设置CorrelationId后触发,若此时上下文未正确关联,可能会导致装饰方法重新生成UUID覆盖手动设置的值。

解决方案

1. 修复类名引用一致性

将配置类的类名改为CorrelationAutoConfiguration,或者修改传播工厂和工具类中的引用路径为CorrelationAutoConfiguration1,确保所有代码引用的是同一个BaggageField实例。

修改后的配置类示例:

@Configuration
public class CorrelationAutoConfiguration { // 修正类名

    public static final BaggageField CORRELATION_ID_BAGGAGE_FIELD = BaggageField.create("correlationId");

    // 其余代码不变
}

2. 验证测试上下文关联

调整测试用例,直接通过Tracer获取当前TraceContext并操作BaggageField,确保上下文正确关联:

@Test
public void correlationId() {
    String correlationId = "test-5";
    // 获取当前上下文的TraceContext
    TraceContext currentContext = tracer.currentTraceContext().context();
    // 直接向当前上下文设置CorrelationId
    CorrelationAutoConfiguration.CORRELATION_ID_BAGGAGE_FIELD.updateValue(currentContext, correlationId);
    // 验证上下文内的值
    assertEquals(correlationId, CorrelationAutoConfiguration.CORRELATION_ID_BAGGAGE_FIELD.getValue(currentContext));
    // 验证工具类获取的值
    assertEquals(correlationId, Correlator.getCorrelationId());
}

3. 确保依赖版本兼容

为micrometer-tracing-bridge-brave指定兼容的版本,避免依赖冲突。例如,对应brave 5.14.0,可使用1.0.0-M1版本:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-brave</artifactId>
    <version>1.0.0-M1</version>
</dependency>

验证结果

修复类名引用后,测试用例中设置的CorrelationId可以被正确获取,链路追踪的BaggageField在测试环境中正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 11:27:02