SpringBoot?實現(xiàn)動態(tài)添加定時任務功能
最近的需求有一個自動發(fā)布的功能, 需要做到每次提交都要動態(tài)的添加一個定時任務

代碼結構

1. 配置類
package com.orion.ops.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* 調度器配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2022/2/14 9:51
*/
@EnableScheduling
@Configuration
public class SchedulerConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(4);
scheduler.setRemoveOnCancelPolicy(true);
scheduler.setThreadNamePrefix("scheduling-task-");
return scheduler;
}
}2. 定時任務類型枚舉
package com.orion.ops.handler.scheduler;
import com.orion.ops.consts.Const;
import com.orion.ops.handler.scheduler.impl.ReleaseTaskImpl;
import com.orion.ops.handler.scheduler.impl.SchedulerTaskImpl;
import lombok.AllArgsConstructor;
import java.util.function.Function;
/**
* 任務類型
*
* @author Jiahang Li
* @version 1.0.0
* @since 2022/2/14 10:16
*/
@AllArgsConstructor
public enum TaskType {
/**
* 發(fā)布任務
*/
RELEASE(id -> new ReleaseTaskImpl((Long) id)) {
@Override
public String getKey(Object params) {
return Const.RELEASE + "-" + params;
}
},
* 調度任務
SCHEDULER_TASK(id -> new SchedulerTaskImpl((Long) id)) {
return Const.TASK + "-" + params;
;
private final Function<Object, Runnable> factory;
* 創(chuàng)建任務
*
* @param params params
* @return task
public Runnable create(Object params) {
return factory.apply(params);
}
* 獲取 key
* @return key
public abstract String getKey(Object params);
}這個枚舉的作用是生成定時任務的 runnable 和 定時任務的唯一值, 方便后續(xù)維護
3. 實際執(zhí)行任務實現(xiàn)類
package com.orion.ops.handler.scheduler.impl;
import com.orion.ops.service.api.ApplicationReleaseService;
import com.orion.spring.SpringHolder;
import lombok.extern.slf4j.Slf4j;
/**
* 發(fā)布任務實現(xiàn)
*
* @author Jiahang Li
* @version 1.0.0
* @since 2022/2/14 10:25
*/
@Slf4j
public class ReleaseTaskImpl implements Runnable {
protected static ApplicationReleaseService applicationReleaseService = SpringHolder.getBean(ApplicationReleaseService.class);
private Long releaseId;
public ReleaseTaskImpl(Long releaseId) {
this.releaseId = releaseId;
}
@Override
public void run() {
log.info("定時執(zhí)行發(fā)布任務-觸發(fā) releaseId: {}", releaseId);
applicationReleaseService.runnableAppRelease(releaseId, true);
}4. 定時任務包裝器
package com.orion.ops.handler.scheduler;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
/**
* 定時 任務包裝器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2022/2/14 10:34
*/
public class TimedTask {
/**
* 任務
*/
private Runnable runnable;
* 異步執(zhí)行
private volatile ScheduledFuture<?> future;
public TimedTask(Runnable runnable) {
this.runnable = runnable;
}
* 提交任務 一次性
*
* @param scheduler scheduler
* @param time time
public void submit(TaskScheduler scheduler, Date time) {
this.future = scheduler.schedule(runnable, time);
* 提交任務 cron表達式
* @param trigger trigger
public void submit(TaskScheduler scheduler, Trigger trigger) {
this.future = scheduler.schedule(runnable, trigger);
* 取消定時任務
public void cancel() {
if (future != null) {
future.cancel(true);
}
}這個類的作用是包裝實際執(zhí)行任務, 以及提供調度器的執(zhí)行方法
5. 任務注冊器 (核心)
package com.orion.ops.handler.scheduler;
import com.orion.ops.consts.MessageConst;
import com.orion.utils.Exceptions;
import com.orion.utils.collect.Maps;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;
/**
* 任務注冊器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2022/2/14 10:46
*/
@Component
public class TaskRegister implements DisposableBean {
private final Map<String, TimedTask> taskMap = Maps.newCurrentHashMap();
@Resource
@Qualifier("taskScheduler")
private TaskScheduler scheduler;
/**
* 提交任務
*
* @param type type
* @param time time
* @param params params
*/
public void submit(TaskType type, Date time, Object params) {
// 獲取任務
TimedTask timedTask = this.getTask(type, params);
// 執(zhí)行任務
timedTask.submit(scheduler, time);
}
* @param cron cron
public void submit(TaskType type, String cron, Object params) {
timedTask.submit(scheduler, new CronTrigger(cron));
* 獲取任務
private TimedTask getTask(TaskType type, Object params) {
// 生成任務
Runnable runnable = type.create(params);
String key = type.getKey(params);
// 判斷是否存在任務
if (taskMap.containsKey(key)) {
throw Exceptions.init(MessageConst.TASK_PRESENT);
}
TimedTask timedTask = new TimedTask(runnable);
taskMap.put(key, timedTask);
return timedTask;
* 取消任務
public void cancel(TaskType type, Object params) {
TimedTask task = taskMap.get(key);
if (task != null) {
taskMap.remove(key);
task.cancel();
* 是否存在
public boolean has(TaskType type, Object params) {
return taskMap.containsKey(type.getKey(params));
@Override
public void destroy() {
taskMap.values().forEach(TimedTask::cancel);
taskMap.clear();
}這個類提供了執(zhí)行, 提交任務的api, 實現(xiàn) DisposableBean 接口, 便于在bean銷毀時將任務一起銷毀
6. 使用
@Resource
private TaskRegister taskRegister;
/**
* 提交發(fā)布
*/
@RequestMapping("/submit")
@EventLog(EventType.SUBMIT_RELEASE)
public Long submitAppRelease(@RequestBody ApplicationReleaseRequest request) {
Valid.notBlank(request.getTitle());
Valid.notNull(request.getAppId());
Valid.notNull(request.getProfileId());
Valid.notNull(request.getBuildId());
Valid.notEmpty(request.getMachineIdList());
TimedReleaseType timedReleaseType = Valid.notNull(TimedReleaseType.of(request.getTimedRelease()));
if (TimedReleaseType.TIMED.equals(timedReleaseType)) {
Date timedReleaseTime = Valid.notNull(request.getTimedReleaseTime());
Valid.isTrue(timedReleaseTime.compareTo(new Date()) > 0, MessageConst.TIMED_GREATER_THAN_NOW);
}
// 提交
Long id = applicationReleaseService.submitAppRelease(request);
// 提交任務
taskRegister.submit(TaskType.RELEASE, request.getTimedReleaseTime(), id);
return id;
}最后
這是一個簡單的動態(tài)添加定時任務的工具, 有很多的改造空間, 比如想持久化可以插入到庫中, 定義一個 CommandLineRunner 在啟動時將定時任務全部加載, 還可以給任務加鉤子自動提交,自動刪除等, 代碼直接cv一定會報錯, 就是一些工具, 常量類會報錯, 改改就好了, 本人已親測可用, 有什么問題可以在評論區(qū)溝通
到此這篇關于SpringBoot 實現(xiàn)動態(tài)添加定時任務功能的文章就介紹到這了,更多相關SpringBoot 定時任務內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spring實戰(zhàn)之獲取其他Bean的屬性值操作示例
這篇文章主要介紹了Spring實戰(zhàn)之獲取其他Bean的屬性值操作,結合實例形式分析了Spring操作Bean屬性值的相關配置與實現(xiàn)技巧,需要的朋友可以參考下2019-12-12

