Spring Boot中@Scheduled无@Observed及try-catch自动生成TraceId可行吗?
问题分析与解决方案
核心问题原因
第一种TaskDecorator实现逻辑错误
Observation.observe(() -> runnable::run)传递的是一个返回Runnable的Supplier,并未真正执行定时任务的业务逻辑,导致观测上下文没有包裹任务的实际执行过程,自然无法生成链路追踪数据。第二种TaskDecorator的@Observed注解无效
@Observed标注在private方法上,而Spring AOP默认无法对private方法进行切面增强(无论JDK动态代理还是CGLIB代理都不会处理private方法),因此观测逻辑根本不会被触发。
正确实现方案
方案一:直接用Observation包裹任务执行
修改ExecutorTaskDecorator,确保观测上下文完整包裹任务执行逻辑:
public class ExecutorTaskDecorator implements TaskDecorator { private final ObservationRegistry observationRegistry; public ExecutorTaskDecorator(ObservationRegistry observationRegistry) { this.observationRegistry = observationRegistry; } @Override public Runnable decorate(Runnable runnable) { return () -> { Observation.createNotStarted("scheduled.task.run", observationRegistry) .observe(runnable::run); }; } }
方案二:public方法配合@Observed(需Spring管理)
如果偏好使用@Observed注解,需将标注注解的方法改为public,并让ExecutorTaskDecorator被Spring容器管理:
@Component public class ExecutorTaskDecorator implements TaskDecorator { private final ObservationRegistry observationRegistry; public ExecutorTaskDecorator(ObservationRegistry observationRegistry) { this.observationRegistry = observationRegistry; } @Override public Runnable decorate(Runnable runnable) { return runWithObserved(runnable); } @Observed(name = "scheduled.task.run") public Runnable runWithObserved(Runnable runnable) { return () -> runnable.run(); } }
同时调整调度器配置,注入Spring管理的装饰器实例:
@Configuration @RequiredArgsConstructor @EnableScheduling public class SchedulerConfiguration { private final ObservationRegistry observationRegistry; private final ExecutorTaskDecorator executorTaskDecorator; @Value("${spring.task.scheduling.pool.size}") private Integer taskSchedulingPoolSize; @Bean public TaskScheduler taskScheduler() { ConcurrentTaskScheduler scheduler = new ConcurrentTaskScheduler(new ScheduledThreadPoolExecutor(taskSchedulingPoolSize)); scheduler.setTaskDecorator(executorTaskDecorator); scheduler.setErrorHandler(new ExceptionHandler()); return scheduler; } }
额外注意事项
- MDC自动传递:使用Brave作为追踪桥接时,观测上下文会自动处理TraceId/SpanId的MDC传递,无需额外配置。
- 异常的观测处理:上述正确实现中,
observe(runnable::run)会自动捕获任务执行的异常并标记观测状态为错误,你的ExceptionHandler只需负责日志打印即可。 - 版本兼容性:你使用的Spring Boot 3.1.3与Micrometer Tracing 1.1.4版本完全兼容,无需调整版本。
验证:修改后,仅需在定时方法上标注@Scheduled,无论执行日志打印还是抛出异常,都会自动生成对应的TraceId和SpanId。
内容的提问来源于stack exchange,提问作者clukz
相关产品推荐
相关产品推荐

