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

代码结构

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 {@Beanpublic 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)) {@Overridepublic String getKey(Object params) {return Const.RELEASE + "-" + params;}},/*** 调度任务*/SCHEDULER_TASK(id -> new SchedulerTaskImpl((Long) id)) {@Overridepublic String getKey(Object params) {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** @param params params* @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;}@Overridepublic 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* @param scheduler scheduler*/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 type   type* @param cron   cron* @param params params*/public void submit(TaskType type, String cron, Object params) {// 获取任务TimedTask timedTask = this.getTask(type, params);// 执行任务timedTask.submit(scheduler, new CronTrigger(cron));}/*** 获取任务** @param type   type* @param params params*/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;}/*** 取消任务** @param type   type* @param params params*/public void cancel(TaskType type, Object params) {String key = type.getKey(params);TimedTask task = taskMap.get(key);if (task != null) {taskMap.remove(key);task.cancel();}}/*** 是否存在** @param type   type* @param params params*/public boolean has(TaskType type, Object params) {return taskMap.containsKey(type.getKey(params));}@Overridepublic void destroy() {taskMap.values().forEach(TimedTask::cancel);taskMap.clear();}}

这个类提供了执行, 提交任务的api, 实现 DisposableBean 接口, 便于在bean销毁时将任务一起销毁

6. 使用

@Resourceprivate 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);// 提交任务if (TimedReleaseType.TIMED.equals(timedReleaseType)) {taskRegister.submit(TaskType.RELEASE, request.getTimedReleaseTime(), id);}return id;}

最后

这是一个简单的动态添加定时任务的工具, 有很多的改造空间, 比如想持久化可以插入到库中, 定义一个 CommandLineRunner 在启动时将定时任务全部加载, 还可以给任务加钩子自动提交,自动删除等, 代码直接cv一定会报错, 就是一些工具, 常量类会报错, 改改就好了, 本人已亲测可用, 有什么问题可以在评论区沟通

SpringBoot 动态添加定时任务相关推荐

  1. django 集成个推_Django动态添加定时任务之djangocelery的使用

    定时任务和周期任务在我们日常工作中应用广泛,例如定时发布.周期巡检等,通常我们会借助Linux下的Crontab来实现,但如何将这一功能搬进我们自研的运维系统呢?借助django-celery即可轻松 ...

  2. java定时执行sql语句_spring中使用quartz动态添加定时任务执行sql

    系统用来每天插入视图数据... 一.数据库表设计 1.接口配置表(t_m_db_interface_config) 2.接口日志表(t_m_db_interface_log) 3.前端配置页面 查询页 ...

  3. Celery 动态添加定时任务生产实践

    一.背景 实际工作中会有一些耗时的异步任务需要使用定时调度,比如发送邮件,拉取数据,执行定时脚本 通过celery 实现调度主要思想是 通过引入中间人redis,启动 worker 进行任务执行 ,c ...

  4. springboot动态添加log4j2的Appender

    使用场景: 一般log4j2的配置都是通过log4j2.xml配置来实现相关的日志操作. 假如项目上使用的的公司封装好的log4j2框架,里面的日志配置都是固定的,如果自己想扩展要么就是升级日志框架( ...

  5. Spring+Quartz实现动态添加定时任务

    老规矩,吃水不忘挖井人:挖井人一,挖井人二. 以上,感谢. 首先引入jar: <!-- quartz定时任务 --><dependency><groupId>org ...

  6. Quartz 分布式定时任务动态添加删除定时任务

    首先对于Quartz的原理和使用这里不再做赘述和讲解,相信大家可以自信查阅文档进行使用.先说一下个人的这个使用背景:项目中需要引入定时任务,框架是springcloud分布式系统然后调研之后决定引入Q ...

  7. Quartz动态添加,修改,删除任务(暂停,任务状态,恢复,最近触发时间)

    首页 博客 学院 下载 图文课 论坛 APP 问答 商城 VIP会员 活动 招聘 ITeye GitChat 写博客 小程序 消息 登录注册 关闭 quartz_Cron表达式一分钟教程 09-05 ...

  8. vue 动态添加click_vue,在模块中动态添加dom节点,并监听

    vue向数组中动态添加数据 vue中数据更新通过v-model实现,向数组中添加数据通过push()实现,向shortcuts数组中动态添加newShortcut对象中的title和action th ...

  9. XXL-Job动态添加任务

    前言 最近项目中涉及到了定时任务相关需求,最终选择了分布式任务调度框架xxl-job,由于我们在使用xxl-job.这里对xxl-job 一些使用做一下简单介绍. 手动定时任务 xxl-job 主要分 ...

  10. Elastic-Job:动态添加任务,支持动态分片

    多情只有春庭月,犹为离人照落花. 概述 因项目中使用到定时任务,且服务部署多实例,因此需要解决定时任务重复执行的问题.即在同一时间点,每一个定时任务只在一个节点上执行.常见的开源方案,如 elasti ...

最新文章

  1. 觉SLAM的主要功能模块分析
  2. 想体验无人商店?去京东他们家直接刷脸!
  3. wordpress-4.4.1 数据库表结构详解
  4. 【讨论】拿什么来维护原创作者的权益?
  5. sqlplus远程连接k8s集群部署的oracle
  6. html5的网络书店图书网站代码_【技能提升】10个编写HTML5的实用小技巧
  7. (前端开发)表格中的行全选、全不选、反选以及数据行背景色变换的示例代码
  8. python渲染光线_python模板渲染配置文件
  9. SpringBoot精通系列-使用Mybatis Generator生成Dao层代码
  10. 快手推出“一站式开放平台”:千亿流量5亿现金扶持经营伙伴
  11. java 解析 ical_ical4j 实现ICS文件的生成和解析
  12. Android应用开发初印象
  13. [4G+5G专题-143]: 一体化小基站-硬件架构设计概述
  14. mysql top percent_SQL Server -- TOP子句/TOP Percent,IN 操作符
  15. 关于ORA-12505, TNS:listener does not currently know of SID given in connect descript的一个解决思路
  16. 冰羚-README.md翻译
  17. Java:实现​lz4格式解压缩算法(附完整源码)
  18. 高新技术计算机应用能力考试,全国计算机信息高新技术考试(OSTA)-人社部职业资格证书...
  19. 解码者:数学探秘之旅——读书笔记(一)
  20. 单片机C语言应用100例(第二版)光盘资料 作者王东峰 陈圆圆 郭向阳

热门文章

  1. 3D动画展示--3D图片旋转展示
  2. 作业(数组)---运行环境winTC(一)
  3. 1980年红色1元纸币值多少钱?
  4. Go中chan引发的协程死锁
  5. Day16_IO框架1(File类, IO流, 字节流字符流, IO异常, Properties)
  6. 使用MISO进行可变剪切的分析
  7. 手机TF 卡 无法读取,提示需要格式化
  8. 联想a30微型计算机,TEP-I-G W13030123 监控模块,监控单元泰坦TEP-I系列微机监控装置...
  9. 领导科学 读书笔记(一)
  10. Android Modem修改点以及修改方法