Spring動態添加定時任務的實現思路

一、背景

在工作中,有些時候我們有些定時任務的執行可能是需要動態修改的,比如: 生成報表,有些項目配置每天的8點生成,有些項目配置每天的10點生成,像這種動態的任務執行時間,在不考慮分佈式執行的情況下,我們可以
使用 Spring Task來簡單的實現。

二、需求和實現思路

1、能夠動態的添加一個定時任務。

Spring中存在一個類ThreadPoolTaskScheduler,它可以實現根據一個cron表達式來調度一個任務,並返回一個ScheduledFuture對象。

可以看到返回值是ScheduledFuture對象

2、能夠取消定時任務的執行。

通過調用上一步的ScheduledFuturecancel方法,就可以將這個任務取消。

3、動態的修改任務執行的時間。

先取消任務。然後在重新註冊一個任務。

4、獲取定時任務執行的異常

ThreadPoolTaskScheduler類中有一個設置ErrorHandler的方法,給自己實現的ErrorHandler即可。

定時任務錯誤處理

提示:

  1. Spring中我們通過@Scheduled註解來實現的定時任務,底層也是通過ThreadPoolTaskScheduler來實現的。可以通過ScheduledAnnotationBeanPostProcessor類來查看。
  2. ThreadPoolTaskScheduler的默認線程數是1,這個需要根據實際的情況進行修改。

三、代碼實現

此處隻給出動態註冊定時任務和取消的定時任務的代碼。

package com.huan.study.task.jobs.tasks;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author huan.fu 2021/7/8 - 下午2:46
 */
@Component
@Slf4j
public class DynamicCronTask implements InitializingBean {

    @Autowired
    private ThreadPoolTaskScheduler taskScheduler;


    private ScheduledFuture<?> scheduledFuture;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 動態啟動一個定時任務
        log.info("註冊一個定時任務:每隔1秒執行一次");
        scheduledFuture = register("* * * * * ?");

        // 取消一個調度
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
                log.info("取消調度");
                scheduledFuture.cancel(false);
                log.info("取消結果:" + scheduledFuture.isCancelled());
                log.info("重新註冊一個定時任務:每隔2秒執行一次");
                register("*/2 * * * * ?");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    private ScheduledFuture<?> register(String cron) {

        // 高版本使用 CronExpression,低版本使用 CronSequenceGenerator
        boolean validExpression = CronExpression.isValidExpression(cron);
        log.info("cron:[{}]是合法的嗎:[{}]", cron, validExpression);

        CronExpression expression = CronExpression.parse(cron);
        LocalDateTime nextExecTime = expression.next(LocalDateTime.now());
        if (null != nextExecTime) {
            log.info("定時任務下次執行的時間為:[{}]", nextExecTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }

        return taskScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                log.info("我執行瞭");
            }
        }, new CronTrigger(cron));
    }
}

四、執行結果

執行結果

五、完整代碼

https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-task

到此這篇關於Spring動態添加定時任務的實現思路的文章就介紹到這瞭,更多相關Spring定時任務內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: