SpringBoot 动态添加定时任务
最近的需求有一个自动发布的功能, 需要做到每次提交都要动态的添加一个定时任务
代码结构
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 动态添加定时任务相关推荐
- django 集成个推_Django动态添加定时任务之djangocelery的使用
定时任务和周期任务在我们日常工作中应用广泛,例如定时发布.周期巡检等,通常我们会借助Linux下的Crontab来实现,但如何将这一功能搬进我们自研的运维系统呢?借助django-celery即可轻松 ...
- java定时执行sql语句_spring中使用quartz动态添加定时任务执行sql
系统用来每天插入视图数据... 一.数据库表设计 1.接口配置表(t_m_db_interface_config) 2.接口日志表(t_m_db_interface_log) 3.前端配置页面 查询页 ...
- Celery 动态添加定时任务生产实践
一.背景 实际工作中会有一些耗时的异步任务需要使用定时调度,比如发送邮件,拉取数据,执行定时脚本 通过celery 实现调度主要思想是 通过引入中间人redis,启动 worker 进行任务执行 ,c ...
- springboot动态添加log4j2的Appender
使用场景: 一般log4j2的配置都是通过log4j2.xml配置来实现相关的日志操作. 假如项目上使用的的公司封装好的log4j2框架,里面的日志配置都是固定的,如果自己想扩展要么就是升级日志框架( ...
- Spring+Quartz实现动态添加定时任务
老规矩,吃水不忘挖井人:挖井人一,挖井人二. 以上,感谢. 首先引入jar: <!-- quartz定时任务 --><dependency><groupId>org ...
- Quartz 分布式定时任务动态添加删除定时任务
首先对于Quartz的原理和使用这里不再做赘述和讲解,相信大家可以自信查阅文档进行使用.先说一下个人的这个使用背景:项目中需要引入定时任务,框架是springcloud分布式系统然后调研之后决定引入Q ...
- Quartz动态添加,修改,删除任务(暂停,任务状态,恢复,最近触发时间)
首页 博客 学院 下载 图文课 论坛 APP 问答 商城 VIP会员 活动 招聘 ITeye GitChat 写博客 小程序 消息 登录注册 关闭 quartz_Cron表达式一分钟教程 09-05 ...
- vue 动态添加click_vue,在模块中动态添加dom节点,并监听
vue向数组中动态添加数据 vue中数据更新通过v-model实现,向数组中添加数据通过push()实现,向shortcuts数组中动态添加newShortcut对象中的title和action th ...
- XXL-Job动态添加任务
前言 最近项目中涉及到了定时任务相关需求,最终选择了分布式任务调度框架xxl-job,由于我们在使用xxl-job.这里对xxl-job 一些使用做一下简单介绍. 手动定时任务 xxl-job 主要分 ...
- Elastic-Job:动态添加任务,支持动态分片
多情只有春庭月,犹为离人照落花. 概述 因项目中使用到定时任务,且服务部署多实例,因此需要解决定时任务重复执行的问题.即在同一时间点,每一个定时任务只在一个节点上执行.常见的开源方案,如 elasti ...
最新文章
- 觉SLAM的主要功能模块分析
- 想体验无人商店?去京东他们家直接刷脸!
- wordpress-4.4.1 数据库表结构详解
- 【讨论】拿什么来维护原创作者的权益?
- sqlplus远程连接k8s集群部署的oracle
- html5的网络书店图书网站代码_【技能提升】10个编写HTML5的实用小技巧
- (前端开发)表格中的行全选、全不选、反选以及数据行背景色变换的示例代码
- python渲染光线_python模板渲染配置文件
- SpringBoot精通系列-使用Mybatis Generator生成Dao层代码
- 快手推出“一站式开放平台”:千亿流量5亿现金扶持经营伙伴
- java 解析 ical_ical4j 实现ICS文件的生成和解析
- Android应用开发初印象
- [4G+5G专题-143]: 一体化小基站-硬件架构设计概述
- mysql top percent_SQL Server -- TOP子句/TOP Percent,IN 操作符
- 关于ORA-12505, TNS:listener does not currently know of SID given in connect descript的一个解决思路
- 冰羚-README.md翻译
- Java:实现​lz4格式解压缩算法(附完整源码)
- 高新技术计算机应用能力考试,全国计算机信息高新技术考试(OSTA)-人社部职业资格证书...
- 解码者:数学探秘之旅——读书笔记(一)
- 单片机C语言应用100例(第二版)光盘资料 作者王东峰 陈圆圆 郭向阳
热门文章
- 3D动画展示--3D图片旋转展示
- 作业(数组)---运行环境winTC(一)
- 1980年红色1元纸币值多少钱?
- Go中chan引发的协程死锁
- Day16_IO框架1(File类, IO流, 字节流字符流, IO异常, Properties)
- 使用MISO进行可变剪切的分析
- 手机TF 卡 无法读取,提示需要格式化
- 联想a30微型计算机,TEP-I-G W13030123 监控模块,监控单元泰坦TEP-I系列微机监控装置...
- 领导科学 读书笔记(一)
- Android Modem修改点以及修改方法