SpringBoot?實(shí)現(xiàn)動(dòng)態(tài)添加定時(shí)任務(wù)功能
最近的需求有一個(gè)自動(dòng)發(fā)布的功能, 需要做到每次提交都要?jiǎng)討B(tài)的添加一個(gè)定時(shí)任務(wù)
代碼結(jié)構(gòu)
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; /** * 調(diào)度器配置 * * @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. 定時(shí)任務(wù)類型枚舉
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; /** * 任務(wù)類型 * * @author Jiahang Li * @version 1.0.0 * @since 2022/2/14 10:16 */ @AllArgsConstructor public enum TaskType { /** * 發(fā)布任務(wù) */ RELEASE(id -> new ReleaseTaskImpl((Long) id)) { @Override public String getKey(Object params) { return Const.RELEASE + "-" + params; } }, * 調(diào)度任務(wù) SCHEDULER_TASK(id -> new SchedulerTaskImpl((Long) id)) { return Const.TASK + "-" + params; ; private final Function<Object, Runnable> factory; * 創(chuàng)建任務(wù) * * @param params params * @return task public Runnable create(Object params) { return factory.apply(params); } * 獲取 key * @return key public abstract String getKey(Object params); }
這個(gè)枚舉的作用是生成定時(shí)任務(wù)的 runnable 和 定時(shí)任務(wù)的唯一值, 方便后續(xù)維護(hù)
3. 實(shí)際執(zhí)行任務(wù)實(shí)現(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ā)布任務(wù)實(shí)現(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("定時(shí)執(zhí)行發(fā)布任務(wù)-觸發(fā) releaseId: {}", releaseId); applicationReleaseService.runnableAppRelease(releaseId, true); }
4. 定時(shí)任務(wù)包裝器
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; /** * 定時(shí) 任務(wù)包裝器 * * @author Jiahang Li * @version 1.0.0 * @since 2022/2/14 10:34 */ public class TimedTask { /** * 任務(wù) */ private Runnable runnable; * 異步執(zhí)行 private volatile ScheduledFuture<?> future; public TimedTask(Runnable runnable) { this.runnable = runnable; } * 提交任務(wù) 一次性 * * @param scheduler scheduler * @param time time public void submit(TaskScheduler scheduler, Date time) { this.future = scheduler.schedule(runnable, time); * 提交任務(wù) cron表達(dá)式 * @param trigger trigger public void submit(TaskScheduler scheduler, Trigger trigger) { this.future = scheduler.schedule(runnable, trigger); * 取消定時(shí)任務(wù) public void cancel() { if (future != null) { future.cancel(true); } }
這個(gè)類的作用是包裝實(shí)際執(zhí)行任務(wù), 以及提供調(diào)度器的執(zhí)行方法
5. 任務(wù)注冊(cè)器 (核心)
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; /** * 任務(wù)注冊(cè)器 * * @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; /** * 提交任務(wù) * * @param type type * @param time time * @param params params */ public void submit(TaskType type, Date time, Object params) { // 獲取任務(wù) TimedTask timedTask = this.getTask(type, params); // 執(zhí)行任務(wù) timedTask.submit(scheduler, time); } * @param cron cron public void submit(TaskType type, String cron, Object params) { timedTask.submit(scheduler, new CronTrigger(cron)); * 獲取任務(wù) private TimedTask getTask(TaskType type, Object params) { // 生成任務(wù) Runnable runnable = type.create(params); String key = type.getKey(params); // 判斷是否存在任務(wù) if (taskMap.containsKey(key)) { throw Exceptions.init(MessageConst.TASK_PRESENT); } TimedTask timedTask = new TimedTask(runnable); taskMap.put(key, timedTask); return timedTask; * 取消任務(wù) 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(); }
這個(gè)類提供了執(zhí)行, 提交任務(wù)的api, 實(shí)現(xiàn) DisposableBean 接口, 便于在bean銷毀時(shí)將任務(wù)一起銷毀
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); // 提交任務(wù) taskRegister.submit(TaskType.RELEASE, request.getTimedReleaseTime(), id); return id; }
最后
這是一個(gè)簡單的動(dòng)態(tài)添加定時(shí)任務(wù)的工具, 有很多的改造空間, 比如想持久化可以插入到庫中, 定義一個(gè) CommandLineRunner 在啟動(dòng)時(shí)將定時(shí)任務(wù)全部加載, 還可以給任務(wù)加鉤子自動(dòng)提交,自動(dòng)刪除等, 代碼直接cv一定會(huì)報(bào)錯(cuò), 就是一些工具, 常量類會(huì)報(bào)錯(cuò), 改改就好了, 本人已親測可用, 有什么問題可以在評(píng)論區(qū)溝通
到此這篇關(guān)于SpringBoot 實(shí)現(xiàn)動(dòng)態(tài)添加定時(shí)任務(wù)功能的文章就介紹到這了,更多相關(guān)SpringBoot 定時(shí)任務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)的示例代碼
- Springboot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)流程詳解
- SpringBoot+Quartz實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)
- SpringBoot設(shè)置動(dòng)態(tài)定時(shí)任務(wù)的方法詳解
- Springboot自帶定時(shí)任務(wù)實(shí)現(xiàn)動(dòng)態(tài)配置Cron參數(shù)方式
- SpringBoot動(dòng)態(tài)定時(shí)功能實(shí)現(xiàn)方案詳解
相關(guān)文章
Java?對(duì)象在?JVM?中的內(nèi)存布局超詳細(xì)解說
這篇文章主要介紹了Java?對(duì)象在?JVM?中的內(nèi)存布局超詳細(xì)解說,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09詳解SpringBoot+Mybatis實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換
這篇文章主要介紹了詳解SpringBoot+Mybatis實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05Java數(shù)組轉(zhuǎn)換為List的四種方式
這篇文章主要介紹了Java開發(fā)技巧數(shù)組轉(zhuǎn)List的四種方式總結(jié),每種方式結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09VsCode搭建Spring Boot項(xiàng)目并進(jìn)行創(chuàng)建、運(yùn)行、調(diào)試
這篇文章主要介紹了VsCode搭建Spring Boot項(xiàng)目并進(jìn)行創(chuàng)建、運(yùn)行、調(diào)試 ,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05spring Data jpa簡介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了spring Data jpa簡介的相關(guān)資料,需要的朋友可以參考下2017-09-09java計(jì)算工作時(shí)間除去節(jié)假日以及雙休日
這篇文章主要為大家詳細(xì)介紹了java計(jì)算工作時(shí)間除去節(jié)假日以及雙休日的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06基于maven搭建一個(gè)ssm的web項(xiàng)目的詳細(xì)圖文教程
這篇文章主要介紹了基于maven搭建一個(gè)ssm的web項(xiàng)目的詳細(xì)教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09