SpringBoot 定时任务进阶——动态 cron、分布式定时任务

发布时间:2026/9/12 8:01:19
SpringBoot 定时任务进阶——动态 cron、分布式定时任务 基础的 Scheduled 注解只能写死 cron 表达式修改需要重启。这篇讲动态定时任务和分布式定时任务。一、ScheduledTaskRegistrar 动态注册ComponentpublicclassDynamicScheduledTask{AutowiredprivateScheduledTaskRegistrartaskRegistrar;publicvoidaddTask(Stringcron,Runnabletask){taskRegistrar.addCronTask(task,cron);}publicvoidremoveTask(Runnabletask){taskRegistrar.removeScheduledTasks();}}二、动态修改 cronComponentpublicclassDynamicCronService{AutowiredprivateScheduledTaskRegistrartaskRegistrar;privateScheduledFuture?future;publicvoidupdateCron(StringnewCron){if(future!null){future.cancel(false);}futuretaskRegistrar.scheduleCronTask(()-{System.out.println(执行定时任务: LocalDateTime.now());},newCron);}}三、配置中心动态 cronComponentRefreshScopepublicclassConfigCenterCron{privatefinalAtomicIntegercounternewAtomicInteger(0);Scheduled(cron${task.report.cron:0 0 2 * * ?})publicvoidreportTask(){log.info(报表任务执行: {},counter.incrementAndGet());}}通过 Nacos 修改配置后定时任务的 cron 表达式自动刷新不需要重启。四、分布式定时任务ComponentpublicclassDistributedScheduledTask{AutowiredprivateStringRedisTemplateredisTemplate;privatestaticfinalStringLOCK_KEYlock:scheduled:report;/** * 每 10 秒执行一次但只有拿到分布式锁的实例才执行 */Scheduled(fixedDelay10000)publicvoidreportTask(){StringlockValueUUID.randomUUID().toString();try{// 尝试获取锁过期时间 8 秒BooleanlockedredisTemplate.opsForValue().setIfAbsent(LOCK_KEY,lockValue,8,TimeUnit.SECONDS);if(Boolean.TRUE.equals(locked)){log.info(获取到锁执行报表任务);// 执行任务...}}finally{// 只释放自己的锁StringvalueredisTemplate.opsForValue().get(LOCK_KEY);if(lockValue.equals(value)){redisTemplate.delete(LOCK_KEY);}}}}五、task.name 做唯一标识ComponentpublicclassInstanceTask{privatestaticfinalLoggerlogLoggerFactory.getLogger(InstanceTask.class);Value(${spring.application.name})privateStringappName;privatefinalStringinstanceIdIdUtil.simpleUUID().substring(0,8);/** * 每台机器各自执行自己的任务 * 适合每台机器独立处理的任务如清理本地日志 */Scheduled(cron0 0 3 * * ?)publicvoidcleanLogTask(){log.info([{}] {} 清理日志,appName,instanceId);}}六、手动启动停止ComponentpublicclassTaskManager{privatefinalMapString,ScheduledFuture?taskMapnewConcurrentHashMap();AutowiredprivateTaskSchedulertaskScheduler;publicvoidstartTask(StringtaskName,Runnabletask,Stringcron){if(taskMap.containsKey(taskName)){log.warn(任务已存在: {},taskName);return;}CronTriggertriggernewCronTrigger(cron);ScheduledFuture?futuretaskScheduler.schedule(task,trigger);taskMap.put(taskName,future);log.info(任务已启动: {},taskName);}publicvoidstopTask(StringtaskName){ScheduledFuture?futuretaskMap.get(taskName);if(future!null){future.cancel(false);taskMap.remove(taskName);log.info(任务已停止: {},taskName);}}publicvoidupdateTaskCron(StringtaskName,Runnabletask,StringnewCron){stopTask(taskName);startTask(taskName,task,newCron);log.info(任务已更新: {} → {},taskName,newCron);}}七、常见问题// 1. Scheduled 默认单线程运行// 如果一个任务卡住了其他所有任务都会卡住// 解决配置线程池ConfigurationpublicclassSchedulingConfig{BeanpublicTaskSchedulertaskScheduler(){ThreadPoolTaskSchedulerschedulernewThreadPoolTaskScheduler();scheduler.setPoolSize(5);scheduler.setThreadNamePrefix(scheduled-);returnscheduler;}}// 2. cron 表达式在线生成// 推荐工具百度搜索 cron 在线 可视化生成总结简单固定任务 → Scheduled(cron ...) 动态修改 cron → TaskScheduler.schedule() 分布式互斥 → Redis 分布式锁 配置中心动态 → RefreshScope 觉得有用的话点赞 关注【张老师技术栈】吧每周更新 Java/Python/MySQL 实战干货不让你白来。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询