Springboot 動態創建定時任務

 Springboot 提供了 @Scheduled 註解來方便我們創建定時任務,可是如果我們需要動態創建定時任務呢?今天我們就一起來看下 Springboot 如何動態創建定時任務。

動態創建定時任務,我最開始想到的是 quartz 框架。可是我們的動態定時任務需求比較簡單,僅僅需要在某個時刻執行某個任務即可,不需要這麼強大的框架。因此,我們的首要方案就是看能不能利用 Springboot 自帶的工具來實現。經過查看源碼,我發現 Springboot 還真提供這些功能,下面我們就簡單來看下。

其中比較重要的代碼,均在 spring-context 的 scheduling 包下。

查看其中的 TaskScheduler 接口,我們發現其中有個方法正和我們的需求相符。

這個方法就是在某個時間執行某個任務,和我們需求一致,接下來我們就來看下怎麼用這個接口。通過 idea 可以發現這個接口有三個實現類,經過對比,我選擇了 ThreadPoolTaskScheduler 這個類 (當然也可以直接使用此接口)。

接下來,我們就用這個類,來實現我們的定時任務的動態創建。

首先,我們先創建一個測試任務,實現 Runnable 接口即可

// java14以下,手動將record類轉爲普通類
public record TestRunnable(String name) implements Runnable {
    @Override
    public void run() {
        System.out.println("定時任務" + name + "執行了");
    }
}

接着,我們對外創建一個 controller

@RestController
public class TestController {
    private final ThreadPoolTaskScheduler taskScheduler;
    // 用ConcurrentHashMap來存放我們的定時任務集合,方便增刪
    private final Map<String, ScheduledFuture<?>> scheduledTasks;
    public TestController(ThreadPoolTaskScheduler taskScheduler) {
        this.taskScheduler = taskScheduler;
        scheduledTasks = new ConcurrentHashMap<>(16);
    }
    @GetMapping("/add")
    public String add(@RequestParam("name") String name) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.SECOND, 10);
        addTask("testTask", new TestRunnable(name), calendar.getTime());
        return "success";
    }
    @GetMapping("/remove")
    public String remove(@RequestParam("name") String name) {
        removeTask(name);
        return "success";
    }
    private void addTask(String taskName, Runnable task, Date startTime) {
        if (scheduledTasks.containsKey(taskName)){
            removeTask(taskName);
        }
        ScheduledFuture<?> schedule = taskScheduler.schedule(task, startTime);
        scheduledTasks.put(taskName, schedule);
    }
    private void removeTask(String taskName) {
        ScheduledFuture<?> scheduledFuture = scheduledTasks.get(taskName);
        scheduledFuture.cancel(true);
        scheduledTasks.remove(taskName);
    }
}

因爲是簡單測試,就先沒有把代碼獨立出來。

然後我們啓動項目,在瀏覽器訪問添加定時任務的接口(設置爲 10 秒後執行)。

過了 10 秒後,確實執行了測試任務。

當然了,上面這個只是簡單的演示。僅僅提供一個思路給大家。作爲項目代碼使用的話,肯定要獨立出來並且要豐富相關功能,這裏由於篇幅,就不過多介紹了,下次如果有時間我可以再分享出來。

查看 Springboot 提供的接口,我們可以發現,Springboot 爲我們提供了豐富的接口用來調度定時任務。大家也可以下去好好研究以下。

package org.springframework.scheduling;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
import org.springframework.lang.Nullable;
// spring調度接口源碼
public interface TaskScheduler {
    default Clock getClock() {
        return Clock.systemDefaultZone();
    }
    @Nullable
    ScheduledFuture<?> schedule(Runnable task, Trigger trigger);
    default ScheduledFuture<?> schedule(Runnable task, Instant startTime) {
        return this.schedule(task, Date.from(startTime));
    }
    ScheduledFuture<?> schedule(Runnable task, Date startTime);
    default ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Instant startTime, Duration period) {
        return this.scheduleAtFixedRate(task, Date.from(startTime), period.toMillis());
    }
    ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period);
    default ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Duration period) {
        return this.scheduleAtFixedRate(task, period.toMillis());
    }
    ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period);
    default ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay) {
        return this.scheduleWithFixedDelay(task, Date.from(startTime), delay.toMillis());
    }
    ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
    default ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Duration delay) {
        return this.scheduleWithFixedDelay(task, delay.toMillis());
    }
    ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay);
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/cU6Ju2Oi5UcF3pjQ9QGcig