前言
目前市面上关于 Spring 链路追踪的资料要么过时,要么残缺。在上一篇文章《彻底搞懂微服务 TraceId 传递:ThreadLocal、TTL 与全链路日志追踪实战》中,我们详细讲解了如何通过 TransmittableThreadLocal (TTL) 手动实现 TraceId 的全链路传递。那套方案能够完美解决异步场景下的上下文传递问题,但需要手动编写不少代码。
本文基于真实迁移经验,介绍企业级的解决方案:Spring Boot 3.0.2 + Micrometer Tracing。这是 Spring 官方推荐的链路追踪方案,给出一套覆盖所有调用场景、可直接用于生产的方案。
技术演进:从 Sleuth 到 Micrometer Tracing
为什么不再使用 Spring Cloud Sleuth?
Spring Cloud Sleuth 是 Spring Boot 2.x 时代的链路追踪组件,但从 Spring Boot 3.0 开始,Sleuth 已停止支持。官方将核心功能迁移到了 Micrometer Tracing 项目。
演进路径:
scss
Spring Boot 2.x → Spring Cloud Sleuth 3.1.x (最终版本)
↓
Spring Boot 3.x → Micrometer Tracing 1.0+ (官方继任者)
Micrometer Tracing 的优势
- 原生集成:Spring Boot 3.x 原生支持,无需额外配置
- 自动化:TraceId/SpanId 自动生成、传递、注入日志
- 零侵入:业务代码无需改动
- 标准化:支持 OpenTelemetry、Zipkin、Brave 等多种后端
项目架构
本文通过一个实战项目演示完整的链路追踪方案,项目包含两个微服务:

核心依赖
pom.xml 配置
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
</parent>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2022.0.1</spring-cloud.version>
</properties>
<dependencies>
<!-- Web 服务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Actuator (包含 Micrometer) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Micrometer Tracing (链路追踪核心) -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<!-- Context Propagation (异步上下文传递) -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>context-propagation</artifactId>
<version>1.0.2</version>
</dependency>
<!-- OpenFeign (服务调用) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Feign + Micrometer 集成 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
</dependency>
</dependencies>
关键点:
- 不需要
spring-cloud-starter-sleuth(已废弃) micrometer-tracing-bridge-brave是链路追踪的核心context-propagation用于异步场景的上下文传递
配置文件
application.yml
yaml
spring:
application:
name: user-service # 服务名称,会自动注入日志
server:
port: 8081
# Micrometer Tracing 配置
management:
tracing:
sampling:
probability: 1.0 # 采样率:1.0 = 100%(开发环境)
# 生产环境建议 0.1(10%)
logback-spring.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProperty scope="context" name="springAppName" source="spring.application.name"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [${springAppName},%X{traceId},%X{spanId}] --- [%15.15t] %-40.40logger{39} : %m%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
日志格式说明:
%X{traceId}:自动注入 TraceId(16位十六进制)%X{spanId}:自动注入 SpanId(8位十六进制)${springAppName}:服务名称
关键实现
1. 异步配置(重点)
异步场景是链路追踪的难点,需要特殊配置才能正确传递 TraceId。
java
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("async-");
// 关键:配置 TaskDecorator 传递上下文
executor.setTaskDecorator(new TaskDecorator() {
@Override
public Runnable decorate(Runnable runnable) {
// 在主线程中捕获上下文快照
ContextSnapshot snapshot = ContextSnapshot.captureAll();
return () -> {
// 在异步线程中恢复上下文
try (ContextSnapshot.Scope scope = snapshot.setThreadLocals()) {
runnable.run();
}
};
}
});
executor.initialize();
return executor;
}
}
工作原理:
2. OpenFeign 客户端
java
@FeignClient(name = "product-service", url = "http://localhost:8082")
public interface ProductFeignClient {
@GetMapping("/product/{productId}")
String getProductInfo(@PathVariable("productId") String productId);
}
自动集成:
- 引入
feign-micrometer依赖后,Feign 会自动在 HTTP 请求头中添加 TraceId - 无需手动编写拦截器
3. RestTemplate 配置
java
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
自动集成:
- Spring Boot 3.x 会自动为 RestTemplate 配置链路追踪拦截器
- 使用
RestTemplateBuilder构建即可
4. 异步服务
java
@Service
public class AsyncService {
private static final Logger log = LoggerFactory.getLogger(AsyncService.class);
@Autowired
private RestTemplate restTemplate;
@Async("taskExecutor") // 使用配置的线程池
public void asyncTask(String userId) {
log.info("【异步任务】开始执行,userId: {}", userId);
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
log.info("【异步任务】执行完成,userId: {}", userId);
}
@Async("taskExecutor")
public void asyncCallProductService(String productId) {
log.info("【异步调用】开始调用商品服务,productId: {}", productId);
// 异步线程中也能正确传递 TraceId
String result = restTemplate.getForObject(
"http://localhost:8082/product/" + productId,
String.class
);
log.info("【异步调用】商品服务返回: {}", result);
}
}
测试验证
测试场景 1:同步调用(OpenFeign)
请求:
bash
curl http://localhost:8081/user/feign/U001
日志输出:
用户服务:
ini
2025-12-14 17:00:00.123 INFO [user-service,abc123def456,abc123de] --- [nio-8081-exec-1] UserController : 【用户服务-Feign】收到请求,userId: U001
商品服务:
ini
2025-12-14 17:00:00.145 INFO [product-service,abc123def456,f456789a] --- [nio-8082-exec-1] ProductController : 【商品服务】收到请求,productId: P001
验证结果:
- TraceId 完全相同:
abc123def456 - 每个服务有独立的 SpanId
测试场景 2:异步调用
请求:
bash
curl http://localhost:8081/user/async/U003
日志输出:
主线程:
ini
2025-12-14 17:03:47.414 INFO [user-service,693e7d733e60,92fcdb11] --- [nio-8081-exec-1] UserController : 【用户服务-异步】收到请求
异步线程 1:
ini
2025-12-14 17:03:47.419 INFO [user-service,693e7d733e60,92fcdb11] --- [async-1] AsyncService : 【异步任务】开始执行
2025-12-14 17:03:48.423 INFO [user-service,693e7d733e60,92fcdb11] --- [async-1] AsyncService : 【异步任务】执行完成
异步线程 2 调用商品服务:
ini
2025-12-14 17:03:47.419 INFO [user-service,693e7d733e60,92fcdb11] --- [async-2] AsyncService : 【异步调用】开始
2025-12-14 17:03:47.503 INFO [user-service,693e7d733e60,92fcdb11] --- [async-2] AsyncService : 【异步调用】成功
商品服务:
ini
2025-12-14 17:03:47.492 INFO [product-service,693e7d733e60,4a4347a4] --- [nio-8082-exec-1] ProductController : 【商品服务】收到请求
验证结果:
- 主线程、异步线程 1、异步线程 2、商品服务的 TraceId 完全相同 :
693e7d733e60 - 异步场景下 TraceId 正确传递
完整调用链路
核心流程图
详细说明
阶段1:请求进入
- HTTP 请求到达服务后,Micrometer Tracing 自动生成 TraceId(16位十六进制)
- TraceId 自动注入到 MDC(Mapped Diagnostic Context),供日志使用
阶段2:业务处理
- 业务逻辑执行过程中,TraceId 一直存储在 ThreadLocal 中
- 所有日志输出自动包含 TraceId 和 SpanId
阶段3:调用下游服务
同步调用(OpenFeign / RestTemplate):
- Micrometer 自动拦截 HTTP 请求
- 自动在 HTTP Header 中添加
traceparent字段(W3C 标准) - 下游服务接收后自动提取 TraceId
异步调用(@Async):
- 提交任务时,
ContextSnapshot.captureAll()捕获当前线程的 TraceId - 异步线程执行前,
setThreadLocals()恢复 TraceId 到新线程 - 异步线程中的 HTTP 调用同样自动传递 TraceId
阶段4:链路传播
- 下游服务从 HTTP Header 提取 TraceId
- 继续传播到更下游的服务
- 整个调用链使用相同的 TraceId
方案对比
手动实现(TTL 方案)vs 企业级方案(Micrometer Tracing)
| 对比项 | 手动实现(TTL) | Micrometer Tracing |
|---|---|---|
| 代码量 | 需要手动编写 Filter、拦截器、上下文管理 | 几乎零代码,只需配置 |
| 异步支持 | 需要配置 TtlRunnable 装饰器 | 需要配置 ContextSnapshot |
| HTTP 调用 | 需要手动实现拦截器 | 自动集成 |
| 日志集成 | 需要手动同步 MDC | 自动注入 |
| 维护成本 | 较高,需要理解原理 | 低,Spring 官方维护 |
| 扩展性 | 灵活但复杂 | 标准化,易于集成 Zipkin 等 |
| 学习曲线 | 陡峭 | 平缓 |
适用场景
手动实现方案适合:
- 非 Spring Boot 项目
- 需要高度定制的场景
- 学习 ThreadLocal 原理
企业级方案适合:
- Spring Boot 3.x 新项目
- 快速落地
- 标准化要求高的团队
常见问题
问题1:异步任务中 TraceId 丢失
原因: 未配置 TaskDecorator
解决:
java
executor.setTaskDecorator(runnable -> {
ContextSnapshot snapshot = ContextSnapshot.captureAll();
return () -> {
try (ContextSnapshot.Scope scope = snapshot.setThreadLocals()) {
runnable.run();
}
};
});
问题2:日志中没有 TraceId
原因: logback 配置未添加 %X{traceId}
解决:
xml
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId},%X{spanId}] %m%n</pattern>
问题3:跨服务 TraceId 不一致
原因: 缺少 feign-micrometer 依赖
解决:
xml
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
</dependency>
项目结构
bash
surfing-tracing-demo/
├── user-service/ # 用户服务 (8081)
│ ├── controller/
│ ├── service/
│ ├── feign/
│ ├── config/
│ │ ├── AsyncConfig.java # 异步配置
│ │ └── RestTemplateConfig.java
│ └── resources/
│ ├── application.yml
│ └── logback-spring.xml
│
└── product-service/ # 商品服务 (8082)
├── controller/
├── service/
└── resources/
├── application.yml
└── logback-spring.xml
启动步骤
1. 编译项目
bash
mvn clean install
2. 启动商品服务
bash
cd product-service
mvn spring-boot:run
3. 启动用户服务
bash
cd user-service
mvn spring-boot:run
4. 测试
bash
# OpenFeign 调用
curl http://localhost:8081/user/feign/U001
# RestTemplate 调用
curl http://localhost:8081/user/rest/U002
# 异步调用
curl http://localhost:8081/user/async/U003
# 综合测试
curl http://localhost:8081/user/all/U004
总结
通过 Spring Boot 3.0.2 + Micrometer Tracing 实现分布式链路追踪,相比手动实现方案有以下优势:
- 开箱即用:引入依赖即可,无需编写大量代码
- 自动化程度高:TraceId 生成、传递、注入日志全自动
- 标准化:符合 Spring 官方规范,易于维护
- 生产就绪:经过大量企业验证
对于新项目,强烈建议使用这套企业级方案。而对于老项目(Spring Boot 2.x),可以继续使用 Spring Cloud Sleuth 3.1.x,等升级到 Spring Boot 3.x 后再迁移。