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

Spring Boot懒初始化模式下@Scheduled定时任务不生效解决方案

Spring Boot 2.6.7 + JDK17 环境下@Scheduled定时任务不执行问题

问题现象

基于Spring Boot 2.6.7、JDK 17搭建的应用中,@Scheduled标注的定时任务完全不执行;在启动类main方法中添加context.getBean(NoPrimaryServiceTasks.class);提前获取对应Bean后,定时任务即可正常运行。尝试使用Spring Boot官方提供的org.springframework.boot.autoconfigure.task.ScheduledBeanLazyInitializationExcludeFilter也无法解决问题。

关联代码

定时任务配置类

@Configuration
@EnableScheduling
public class SchedulingConfigurerConfiguration implements SchedulingConfigurer {
    
    @Value("${schedule.pool}")
    private int DYNO_CORES;

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        var taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(DYNO_CORES * 4);
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);
    }

       
    @Bean
    SimpleAsyncTaskExecutor executor() {
        var executor = new SimpleAsyncTaskExecutor("bg_tasks_");
        executor.setConcurrencyLimit(UNBOUNDED_CONCURRENCY);//these jobs are mainly IO-bound, so let's not set a limit for now
        return executor;
    }
}

定时任务服务类

@Slf4j
@Service
public class NoPrimaryServiceTasks {
    @Scheduled(fixedDelay = 1000, initialDelay = 1000 )
    public void checkBacklogSize() {
        log.info("logzzz");
    }
}

问题根因

  • 在configureTasks方法中手动实例化的ThreadPoolTaskScheduler没有被注册为Spring容器管理的Bean,手动调用initialize()的时机早于@Scheduled注解所在Bean的后置处理流程,导致ScheduledAnnotationBeanPostProcessor扫描@Scheduled方法时,没有正确关联到调度器。
  • Spring Boot 2.6+ 版本默认对无显式依赖引用的Bean采用懒初始化策略,定时任务类没有被其他Bean注入依赖,因此启动阶段不会被实例化,其@Scheduled方法自然不会被注册到任务调度器中。
  • 官方ScheduledBeanLazyInitializationExcludeFilter不生效的原因是自定义SchedulingConfigurer的加载触发了ScheduledTaskRegistrar提前初始化,此时过滤器还未完成对定时任务Bean的排除规则加载。
  • 原代码中UNBOUNDED_CONCURRENCY常量未指定所属类,会直接出现编译错误,该常量属于SimpleAsyncTaskExecutor类。

修复方案

  1. 将ThreadPoolTaskScheduler声明为Spring容器管理的Bean,由容器负责生命周期管理,不要在configureTasks方法中手动实例化和初始化。
  2. 给定时任务类添加@Lazy(false)注解,强制容器在启动阶段立即实例化该类,保证@Scheduled方法能被后置处理器扫描到。
  3. 修正常量引用的编译错误,给异步执行器Bean指定明确名称,避免和调度器Bean产生冲突。

修复后配置类代码

@Configuration
@EnableScheduling
public class SchedulingConfigurerConfiguration implements SchedulingConfigurer {
    
    @Value("${schedule.pool}")
    private int dynoCores;

    @Bean(destroyMethod = "shutdown", name = "taskScheduler")
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(dynoCores * 4);
        taskScheduler.setThreadNamePrefix("scheduled-pool-");
        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        taskScheduler.setAwaitTerminationSeconds(30);
        return taskScheduler;
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setTaskScheduler(taskScheduler());
    }

    @Bean(name = "bgTaskExecutor")
    SimpleAsyncTaskExecutor bgTaskExecutor() {
        var executor = new SimpleAsyncTaskExecutor("bg_tasks_");
        executor.setConcurrencyLimit(SimpleAsyncTaskExecutor.UNBOUNDED_CONCURRENCY);
        return executor;
    }
}

修复后定时任务类代码

@Slf4j
@Service
@Lazy(false)
public class NoPrimaryServiceTasks {
    @Scheduled(fixedDelay = 1000, initialDelay = 1000 )
    public void checkBacklogSize() {
        log.info("logzzz");
    }
}

如果项目全局开启了懒加载(配置了spring.main.lazy-initialization=true),可以额外在配置类上添加@Import(NoPrimaryServiceTasks.class),显式导入定时任务类,保证其被容器提前扫描加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 08:21:52