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

Spring Boot中@Scheduled无@Observed及try-catch自动生成TraceId可行吗?

问题分析与解决方案

核心问题原因

  1. 第一种TaskDecorator实现逻辑错误
    Observation.observe(() -> runnable::run) 传递的是一个返回Runnable的Supplier,并未真正执行定时任务的业务逻辑,导致观测上下文没有包裹任务的实际执行过程,自然无法生成链路追踪数据。

  2. 第二种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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 16:35:23