当前位置: 首页 > article >正文

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注解通常有三种调度方式,fixedRatefixedDelaycron

  • 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已经足够用了。


http://www.kler.cn/a/15810.html

相关文章:

  • 【HAProxy09】企业级反向代理HAProxy高级功能之压缩功能与后端服务器健康性监测
  • MySQL缓存使用率超过80%的解决方法
  • 实用且免费的 IP 地域查询 API 接口推荐
  • SpringBoot 2.2.10 无法执行Test单元测试
  • [Codesys]常用功能块应用分享-BMOV功能块功能介绍及其使用实例说明
  • Ubuntu+ROS 机械臂拾取和放置
  • 数据库预科与增删查改(CURD)
  • 手搓实现矩阵操作
  • 什么是阻抗?影响阻抗的因素有哪些?
  • java第三天
  • 区块链在元宇宙中的作用(二)
  • ShareSDK 抖音平台注册
  • ubuntu中安装VMware Tools,实现Windows文件拖入Ubuntu
  • Java——一维数组和二维数组(主要详讲一维数组)
  • Vivado约束添加方法:一文全面解析IO和时序约束
  • RSA算法仿真模拟
  • package.json第三方配置
  • Linux 中安装配置 LVS 实现前向代理负载均衡的步骤
  • C++linux高并发服务器项目实践 day4
  • vueuse常用hooks
  • docker登录harbor、K8s拉取镜像报http: server gave HTTP response to HTTPS client
  • Scala语言入门以及基本语法
  • 【Java入门合集】第二章Java语言基础(一)
  • 简单认识 Postman界面操作
  • 千耘导航让普通棉农享受到科技红利
  • 多维评测指标解读2022MSU世界编码器大赛结果