Spring中的Schedule动态添加修改定时任务详解
作者:杨某人信了你的邪
Spring Schedule如何动态添加修改定时任务
1、快速开始
通常情况下,我们使用的功能很简单,只需要在配置类上加一个@EnableScheduling注解,然后在Bean对应的方法上添加@Scheduled注解即可。但一般情况下,还会自定义对应的线程池等信息,如下所示。
@EnableScheduling @Configuration public class SchedulerConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { ThreadPoolTaskScheduler taskScheduler = threadPoolTaskScheduler(); taskRegistrar.setScheduler(taskScheduler); } @Bean public ThreadPoolTaskScheduler threadPoolTaskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(Runtime.getRuntime().availableProcessors() / 3 + 1); scheduler.setThreadNamePrefix("scheduler-"); scheduler.setRemoveOnCancelPolicy(true); return scheduler; } }
@Scheduled注解通常有三种调度方式,fixedRate、fixedDelay和cron。
- fixedRate:定时执行,如@Scheduled(fixedRate= 2000)会每隔两秒执行一次
- fixedDelay:固定延迟,如@Scheduled(fixedDelay= 2000)会在上次任务执行完成后,延迟两秒再触发下一次
- cron:自定义规则,比较复杂,功能更强大
2、Schedule的动态修改
以cron表达式任务为例,在上面的基础上,如果有如下定时任务,在每天凌晨一点执行一次,但是后面发现时间不合适,需要修改触发时间为凌晨两点,按照现有的方式,通常只能修改代码重新部署了。
@Scheduled(cron = "0 0 1 * * ?") public void foo() { // do something }
可能有人会问,为啥不用Quartz?Quartz自然是非常方便强大的,但不是本篇要讲的内容,本篇就偏要使用SpringSchedule来实现动态的cron表达式任务。
在上面的快速开始一节中,通过configureTasks,我们可以拿到ScheduledTaskRegistrar实例,在这个实例中提供了很多的操作定时任务方法
public ScheduledTask scheduleTriggerTask(TriggerTask task) {/**/} public ScheduledTask scheduleCronTask(CronTask task) {/**/} public ScheduledTask scheduleFixedRateTask(IntervalTask task) {/**/} public ScheduledTask scheduleFixedRateTask(FixedRateTask task) {/**/} public ScheduledTask scheduleFixedDelayTask(IntervalTask task) {/**/} public ScheduledTask scheduleFixedDelayTask(FixedDelayTask task) {/**/}
修改第一步中的配置如下,为了操作简单,这里直接通过ApplicationRunner来进行测试
@Slf4j @EnableScheduling @Configuration public class SchedulerConfig implements SchedulingConfigurer, ApplicationRunner { private ScheduledTaskRegistrar taskRegistrar; @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { ThreadPoolTaskScheduler taskScheduler = threadPoolTaskScheduler(); taskRegistrar.setScheduler(taskScheduler); this.taskRegistrar = taskRegistrar; } @Bean public ThreadPoolTaskScheduler threadPoolTaskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(Runtime.getRuntime().availableProcessors() / 3 + 1); scheduler.setThreadNamePrefix("scheduler-"); scheduler.setRemoveOnCancelPolicy(true); return scheduler; } @Override public void run(ApplicationArguments args) throws Exception { CronTask cronTask = new CronTask(() -> log.info("foo-----------"), "0/2 * * * * ?"); ScheduledTask fooTask = taskRegistrar.scheduleCronTask(cronTask); ExecutorService executor = Executors.newSingleThreadExecutor(Thread::new); executor.execute(() -> { try { // 等10秒 TimeUnit.SECONDS.sleep(10); Runnable runnable = fooTask.getTask().getRunnable(); // 停止foo任务 fooTask.cancel(); // 重新添加,并修改触发时间为每3秒一次 taskRegistrar.scheduleCronTask(new CronTask(runnable, "0/3 * * * * ?")); // 再添加一个bar任务,每秒执行一次 taskRegistrar.scheduleCronTask(new CronTask(() -> log.info("bar..."), "0/1 * * * * ?")); } catch (InterruptedException e) { e.printStackTrace(); } }); } }
日志如下,从日志中可以看到,上面的操作是成功的,而且也是非常方便的,可以很方便的动态添加定时任务,其余几个方法就不写出来了,感兴趣的可以自己试一下。
2023-04-28 16:38:21.547 INFO 8592 --- [ main] com.example.SpringBootQuartzApplication : Started SpringBootQuartzApplication in 1.101 seconds (JVM running for 1.563)
2023-04-28 16:38:22.002 INFO 8592 --- [ scheduler-1] com.example.task.SchedulerConfig : foo-----------
2023-04-28 16:38:24.001 INFO 8592 --- [ scheduler-1] com.example.task.SchedulerConfig : foo-----------
2023-04-28 16:38:26.001 INFO 8592 --- [ scheduler-2] com.example.task.SchedulerConfig : foo-----------
2023-04-28 16:38:28.001 INFO 8592 --- [ scheduler-1] com.example.task.SchedulerConfig : foo-----------
2023-04-28 16:38:30.002 INFO 8592 --- [ scheduler-3] com.example.task.SchedulerConfig : foo-----------
2023-04-28 16:38:32.002 INFO 8592 --- [ scheduler-1] com.example.task.SchedulerConfig : bar
2023-04-28 16:38:33.000 INFO 8592 --- [ scheduler-2] com.example.task.SchedulerConfig : bar
2023-04-28 16:38:33.000 INFO 8592 --- [ scheduler-3] com.example.task.SchedulerConfig : foo-----------
2023-04-28 16:38:34.002 INFO 8592 --- [ scheduler-3] com.example.task.SchedulerConfig : bar
2023-04-28 16:38:35.001 INFO 8592 --- [ scheduler-3] com.example.task.SchedulerConfig : bar
2023-04-28 16:38:36.001 INFO 8592 --- [ scheduler-1] com.example.task.SchedulerConfig : foo-----------
2023-04-28 16:38:36.001 INFO 8592 --- [ scheduler-3] com.example.task.SchedulerConfig : bar
2023-04-28 16:38:37.002 INFO 8592 --- [ scheduler-3] com.example.task.SchedulerConfig : bar
2023-04-28 16:38:38.002 INFO 8592 --- [ scheduler-3] com.example.task.SchedulerConfig : bar
2023-04-28 16:38:39.001 INFO 8592 --- [ scheduler-1] com.example.task.SchedulerConfig : foo-----------
2023-04-28 16:38:39.001 INFO 8592 --- [ scheduler-3] com.example.task.SchedulerConfig : bar
当然,上面的例子中,因为都是在run方法内,所以没那么多讲究,一般在正式使用的时候,会在scheduleXXXTask返回的ScheduledTask实例保存起来,比如保存到map中并给一个唯一key之类的,以方便后续操作,又或者自定义类实现Runable接口并在其中指定能唯一标识这个任务的方法。具体如何实现,就看具体场景了。
quartz以及xxl-job等框架也是非常优秀的任务调度框架,提供的功能更为强大,但对于比较简单的小项目来说,没有引入的必要,Spring Schedule已经足够用了。
到此这篇关于Spring中的Schedule动态添加修改定时任务详解的文章就介绍到这了,更多相关Schedule动态添加修改定时任务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!