配置Micrometer实现异步操作自动创建新Span
解决Spring Boot 3.2异步方法生成新Span的问题
核心问题分析
你的配置仅实现了上下文传递,但未在异步任务执行阶段触发新Span的创建;手动在getAsyncExecutor()里生成Span是在配置初始化时执行的,而非每个异步任务执行时,因此实际方法仍使用外部Span。另外@NewSpan需要Micrometer Tracing的切面支持,且异步执行器要正确绑定追踪上下文。
正确实现步骤
1. 确认依赖配置
确保引入Micrometer Tracing相关依赖(以Maven为例):
<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing-bridge-brave</artifactId> </dependency>
2. 自定义异步执行器,在任务执行时创建新Span
不要在执行器初始化阶段创建Span,而是包装任务,在任务执行时生成新Span并绑定上下文:
@Configuration class MicrometerConfig implements AsyncConfigurer { private final Tracer tracer; private final ContextSnapshotFactory contextSnapshotFactory = ContextSnapshotFactory.builder().build(); // 注入Tracer实例 public MicrometerConfig(Tracer tracer) { this.tracer = tracer; } @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.initialize(); // 包装执行逻辑,确保每个异步任务生成独立Span return runnable -> { // 捕获当前上下文(包含父Span信息) ContextSnapshot snapshot = contextSnapshotFactory.captureAll(); executor.execute(() -> { try (var ignored = snapshot.wrap()) { // 创建新Span,关联父Span作为子Span Span newSpan = tracer.nextSpan().name("async-task").start(); try (Tracer.SpanInScope spanInScope = tracer.withSpan(newSpan)) { runnable.run(); } finally { // 必须结束Span,避免资源泄漏 newSpan.end(); } } }); }; } }
3. 正确使用@NewSpan注解
若要使用@NewSpan,需满足以下条件:
- 异步方法所在类是Spring管理的Bean;
- 避免在同一类中直接调用
@Async方法(切面无法生效),需通过Bean代理调用; - 可结合
@SpanTag传递自定义标签,示例:
@Service public class AsyncService { @Async @NewSpan(name = "custom-async-operation") public void executeAsyncTask(@SpanTag("task-id") String taskId) { // 业务逻辑实现 } }
4. 配置日志格式验证结果
在application.yml中配置日志格式,确保TraceId和SpanId输出:
logging: pattern: level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
关键注意事项
- 新Span必须在任务执行时创建,而非执行器初始化阶段;
- 需正确捕获父上下文,确保新Span与父Span形成父子关联;
- 任务执行完毕后必须调用
newSpan.end()结束Span,防止Span泄漏。
内容的提问来源于stack exchange,提问作者Joseph K. Strauss
相关产品推荐
相关产品推荐

