Spring Boot定时任务调度动态配置,规避定时器硬编码

定时任务在业务生产中有着十分重要的作用,Spring Boot中,基于@Scheduled注解可以快速地实现定时任务。,一般定时任务都是按固定的频率来执行,但是因为一些外部因素需要调整频率时,就得重新走一遍编码、打包、部署的流程。本文将与读者一探索如何解决定时器硬编码问题。

定时器中常用Cron表达式来配置定时任务执行时间,Cron是一种描述定时任务调度的字符串,非常灵活,我们本文的核心就是消除Cron表达式硬编码。对Cron表达式感兴趣的朋友,可以阅读之前的文章。

文章链接:如何使用Cron表达式配置定时任务

一、常规定时器配置

在了解动态定时器配置之前,我们先一起回顾一下,常规定时器任务配置是怎么实现的。

1、启动定时任务

在Spring Boot中可以通过 @EnableScheduling 注解开启定时任务。一般是在Spring Boot的这一类上添加此注解。

@SpringBootApplication@EnableSchedulingpublic class CustomApplication {
    public static void main(String[] args) {        SpringApplication.run(DuckdbApplication.class, args);    }
}

2、创建定时任务

创建定时任务是使用 @Scheduled 注解指定执行频率。我们将使用Cron表达式描述任务的调度时间。这里我们配置每20秒执行一次。

@Componentpublic class FixedScheduler {
    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
    @Scheduled(cron = "0/20 * * * * ?")    public void task1() {        System.out.println("任务1执行。当前时间:"+ dateTimeFormatter.format(LocalDateTime.now()));    }}

项目启动后,执行结果如下:

任务1执行。当前时间:13:38:40任务1执行。当前时间:13:39:00任务1执行。当前时间:13:39:20任务1执行。当前时间:13:39:40任务1执行。当前时间:13:40:00任务1执行。当前时间:13:40:20任务1执行。当前时间:13:40:40....

3、调度分析

上述示例是平时大家创建定时任务使用比较多的方式,这种方式,也是最常用的,但是我们想要更灵活的配置,比较增加一个状态位,根据状态位打开或关闭任务,或是改变执行频率就不能实现了,原因在于Cron表达式是硬编码。不能动态改变。

二、动态定时任务配置

动态定时任务配置与硬编码定时任务不同的地方在于任务的创建,第一步都是通过 @EnableScheduling 注解开启定时任务。下面我们创建一个动态定时任务。

/*** @Author: 黑曜石* @Date: 2024-11-12* @Description: 创建动态定时任务* @VERSION: 0.1*/@Componentpublic class DynamicScheduler {
    @Autowired    ThreadPoolTaskScheduler taskScheduler;
    private ScheduledFuture<?> scheduledFuture = null;
    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
    // 当前执行的Cron表达式    private String currCron;
    /**     * 设置任务     * @param cron cron表达式     */    public void setTask(String cron) {        this.currCron = cron;
        pause();                System.out.println("==== 设置新任务("+cron+") =====");        // 创建定时任务        scheduledFuture = taskScheduler.schedule(              () -> System.out.println("任务2执行。当前时间:"+ dateTimeFormatter.format(LocalDateTime.now()))                , new CronTrigger(cron));    }
    /**     * 暂停当前任务     */    public void pause() {        if (scheduledFuture != null) {            // 停止之前的任务            scheduledFuture.cancel(false);            scheduledFuture = null;        }    }
    /**     * 启动当前任务     */    public void start() {        if (scheduledFuture == null && StringUtils.hasText(this.currCron)) {            setTask(currCron);        }    }}

上述示例中,核心在于停止之前的任务和动态创建定时任务。

// 停止之前的定时任务scheduledFuture.cancel(false);
// 创建新的定时任务scheduledFuture = taskScheduler.schedule(        () -> System.out.println("任务2执行。当前时间:"+ dateTimeFormatter.format(LocalDateTime.now()))        , new CronTrigger(cron));

现在我们在项目启动后,调用 setTask 方法设置默认的定时任务,假设我们设置默认调度为20秒一次("0/20 * * * * ?")。在运行一段时间后我们修改为10秒一次("0/10 * * * * ?")。输出如下:

==== 设置新任务(0/20 * * * * ?) =====任务2执行。当前时间:21:28:00任务2执行。当前时间:21:28:20任务2执行。当前时间:21:28:40任务2执行。当前时间:21:29:00==== 设置新任务(0/10 * * * * ?) =====任务2执行。当前时间:21:29:20任务2执行。当前时间:21:29:30任务2执行。当前时间:21:29:40任务2执行。当前时间:21:29:50......

上述示例仅供参与,在实际生产中,大家可根据实际情况包装自己的类。在上述示例中,任务的实现是使用Lambda表达式,感兴趣的读者,可以参考之前的文章:Java后端:通过Function函数式接口与Lambda表达式简化代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值