最近的需求有一个自动发布的功能, 需要做到每次提交都要动态的添加一个定时任务

代码结构

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 {
- /**
- * 发布任务
- */
- 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;
- * 创建任务
- *
- * @param params params
- * @return task
- public Runnable create(Object params) {
- return factory.apply(params);
- }
- * 获取 key
- * @return key
- public abstract String getKey(Object params);
- }
这个枚举的作用是生成定时任务的 runnable 和 定时任务的唯一值, 方便后续维护
3. 实际执行任务实现类
- package com.orion.ops.handler.scheduler.impl;
-
- import com.orion.ops.service.api.ApplicationReleaseService;
- import com.orion.spring.SpringHolder;
- import lombok.extern.slf4j.Slf4j;
- /**
- * 发布任务实现
- *
- * @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("定时执行发布任务-触发 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;
- * 异步执行
- 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);
- }
- }
这个类的作用是包装实际执行任务, 以及提供调度器的执行方法
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);
- // 执行任务
- 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();
- }
这个类提供了执行, 提交任务的api, 实现 DisposableBean 接口, 便于在bean销毁时将任务一起销毁
6. 使用
- @Resource
- private TaskRegister taskRegister;
-
- /**
- * 提交发布
- */
- @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;
- }
最后
这是一个简单的动态添加定时任务的工具, 有很多的改造空间, 比如想持久化可以插入到库中, 定义一个 CommandLineRunner 在启动时将定时任务全部加载, 还可以给任务加钩子自动提交,自动删除等, 代码直接cv一定会报错, 就是一些工具, 常量类会报错, 改改就好了, 本人已亲测可用, 有什么问题可以在评论区沟通
到此这篇关于SpringBoot 实现动态添加定时任务功能的文章就介绍到这了,更多相关SpringBoot 定时任务内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!