spring动态控制定时任务
在spring框架中,对于简单的定时任务,可以使用 @Scheduled 注解实现,在实际项目中,经常需要动态的控制定时任务,比如通过接口增加、启动、停止、删除定时任务,动态的改变定时任务的执行时间等。
我们可以通过编码的方式动态控制定时任务,具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-dynamic-scheduler
一、概述
在spring框架可以通过 CronTask 和 TaskScheduler 动态控制定时任务,实现定时任务的动态更新,比如修改定时任务的执行时间,这个是 @Scheduled 无法实现的。采用编码控制动态任务的方式,我们还可以把动态任务执行信息保存到数据库中,通过数据库里的任务配置数据来动态控制定时任务,也可以通过接口来动态控制定时任务。
二、配置定时任务
首先,同 @Scheduled 注解的方式一样,动态控制定时任务也需要使用 @EnableScheduling 注解来开启定时任务功能:
然后通过实现 SchedulingConfigurer 接口来对动态任务进行配置:
@Component
public class MyScheduler implements SchedulingConfigurer {private ScheduledTaskRegistrar taskRegistrar;private final ConcurrentHashMap<Long, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<>();@Overridepublic void configureTasks(@NonNull ScheduledTaskRegistrar taskRegistrar) {ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();threadPoolTaskScheduler.setPoolSize(10);// Set the pool of threadsthreadPoolTaskScheduler.setThreadNamePrefix("sys-scheduler");threadPoolTaskScheduler.initialize();this.taskRegistrar = taskRegistrar;this.taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);}@PreDestroypublic void destroy() {this.taskRegistrar.destroy();}
}
通过上面的代码,我们就启用了动态任务的基本能力,为动态任务指定了执行线程池。
三、动态更新定时任务
更新定时任务通过 CronTask 和 TaskScheduler 来实现,我们新增一个注册定时任务的方法:
public void registerTask(TaskData taskData) {//如果配置一致,则不需要重新创建定时任务if (scheduledFutures.containsKey(taskData.getId())&& cronTasks.get(taskData.getId()).getExpression().equals(taskData.getExpression())) {return;}//如果策略执行时间发生了变化,则取消当前策略的任务if (scheduledFutures.containsKey(taskData.getId())) {scheduledFutures.remove(taskData.getId()).cancel(false);cronTasks.remove(taskData.getId());}CronTask task = new CronTask(taskData, taskData.getExpression());TaskScheduler scheduler = taskRegistrar.getScheduler();if (scheduler != null) {ScheduledFuture<?> future = scheduler.schedule(task.getRunnable(), task.getTrigger());if (future != null) {scheduledFutures.put(taskData.getId(), future);}}}
我们新增了一个 registerTask 方法用于注册定时任务,入参中 TaskData 是定时任务的配置数据,为了简单,我们把配置数据和执行代码放到了一起:
@Slf4j
@Data
@Entity
public class TaskData implements Runnable {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String expression;@Transient@Overridepublic void run() {log.info("{} is running with expression {}", this.getName(), this.getExpression());}
}
核心代码是创建一个 CronTask 对象,该对象包含两个参数:Runnable 方法和 cron 表达式。
CronTask 对象创建好后,通过 ScheduledTaskRegistrar 对定时任务进行注册,注册完成后,定时任务就会在cron表达式指定的时间点开始执行了。
执行的代码就是 Runnable 参数指定的方法。
四、动态停止定时任务
为了能够动态停止定时任务,我们在注册定时任务时,把注册结果放到了一个Map中:
private final ConcurrentHashMap<Long, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<>();ScheduledFuture<?> future = scheduler.schedule(task.getRunnable(), task.getTrigger());if (future != null) {scheduledFutures.put(taskData.getId(), future);}
新增停止定时任务的方法:
public void stop(Long id) {if (scheduledFutures.containsKey(id)) {scheduledFutures.remove(id).cancel(false);}}
该方法需要传入定时任务的id,由于我们把定时任务信息保存到了 scheduledFutures 这个Map中,所以可以根据任务id参数查找到对应的定时任务信息,然后调用对应的 cancel方法来停止定时任务。
五、通过接口控制定时任务
通过上面的步骤我们已经具备了动态控制定时任务的基本能力,下面增加接口来控制定时任务:
@EnableScheduling
@SpringBootApplication
@RestController
public class DemoApplication {@Autowiredprivate MyScheduler myScheduler;@Autowiredprivate TaskDataRepository taskDataRepository;public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@RequestMapping("/register")public TaskData register(String name,@RequestParam(name = "expression", required = false, defaultValue = "0/1 * * * * ?") String expression) {TaskData taskData = taskDataRepository.findOneByName(name).orElse(new TaskData());taskData.setName(name);taskData.setExpression(expression);taskData = taskDataRepository.save(taskData);myScheduler.registerTask(taskData);return taskData;}@RequestMapping("/stop")public void stop(Long id) {taskDataRepository.findById(id).ifPresent(taskData -> {myScheduler.stop(id);});}
}
我们提供了 register 和 stop 两个接口,这两个接口会在改变动态任务执行数据时,先将数据保存到数据库中,对定时任务进行持久化,避免程序重启后定时任务都丢失。
程序启动后,我们首先调用 register 接口新增一个定时任务:
http://localhost:8080/register?name=test
接口调用后,在日志中可以看到定时任务开始执行了:
2024-01-07T18:02:09.003+08:00 INFO 23012 --- [ sys-scheduler5] c.s.springdynamicscheduler.TaskData : test is running with expression 0/1 * * * * ?
2024-01-07T18:02:10.005+08:00 INFO 23012 --- [ sys-scheduler3] c.s.springdynamicscheduler.TaskData : test is running with expression 0/1 * * * * ?
2024-01-07T18:02:11.012+08:00 INFO 23012 --- [ sys-scheduler3] c.s.springdynamicscheduler.TaskData : test is running with expression 0/1 * * * * ?
再调用 stop 接口,通过日志可以发现定时任务停止了执行:
http://localhost:8080/stop?id=1
相关文章:
spring动态控制定时任务
在spring框架中,对于简单的定时任务,可以使用 Scheduled 注解实现,在实际项目中,经常需要动态的控制定时任务,比如通过接口增加、启动、停止、删除定时任务,动态的改变定时任务的执行时间等。 我们可以通过…...
3. Mybatis 中SQL 执行原理
2. Mybatis 中SQL 执行原理 这里有两种方式,一种为常用的 Spring 依赖注入 Mapper 的方式。另一种为直接使用 SqlSessionTemplate 执行 Sql 的方式。 Spring 依赖注入 Mapper 的方式 Mapper 接口注入 SpringIOC 容器 Spring 容器在扫描 BeanDefinition 阶段会扫…...
第一次在RUST官方论坛上留言发布我的Rust板箱
第一次在RUST官方论坛上发帖子,有点紧张~地址在这里: 【My Rust Crate】obtains linux local information - The Rust Programming Language Forum (rust-lang.org)...
LabVIEW 智能化矿用定向钻机液压系统监测
简介 在矿用定向钻机的液压系统监测中,实现实时监控和异常预警对于保障设备运行的稳定性至关重要。传统的人工监测方法效率低下而且准确性不能满足要求,针对这种情况采用 LabVIEW 开发平台,设计并实现了一套智能化矿用定向钻机液压系统的状态…...
GO数据库操作
Golang 出色的 ORM 库为 GORM。 官网文档:https://gorm.io/docs/ 我们来说说增删改查的用法,更深入的研究可以去官网看看。 GORM功能概览: 关联(有一个、有多个、属于、多对多、多态性、单表继承)挂钩(创…...
PyTorch简单理解ChannelShuffle与数据并行技术解析
目录 torch.nn子模块详解 nn.ChannelShuffle 用法与用途 使用技巧 注意事项 参数 示例代码 nn.DataParallel 用法与用途 使用技巧 注意事项 参数 示例 nn.parallel.DistributedDataParallel 用法与用途 使用技巧 注意事项 参数 示例 总结 torch.nn子模块详…...
MySQL 8查询语句之查询所有字段、特定字段、去除重复字段、Where判断条件
《MySQL 8创建数据库、数据表、插入数据并且查询数据》里边有我使用到的数据。 再使用下方的语句补充一些数据: insert into Bookbought.bookuser(id,username,userphone,userage,sex,userpassword) values (11,Book Break,22245678911,18,male,good#111); insert…...
LLaMA-Factory添加adalora
感谢https://github.com/tsingcoo/LLaMA-Efficient-Tuning/commit/f3a532f56b4aa7d4200f24d93fade4b2c9042736和https://github.com/huggingface/peft/issues/432的帮助。 在LLaMA-Factory中添加adalora 1. 修改src/llmtuner/hparams/finetuning_args.py代码 在FinetuningArg…...
多端多用户万能DIY商城系统源码:自营+多商户入驻商城系统 独立部署 带完整的安装代码包以及搭建教程
电子商务行业日新月异,许多企业希望能够通过线上商城拓展业务。但是,传统商城系统往往无法满足多样化、个性化的需求,而且开发周期长、成本高。罗峰就来给大家分享一款多端多用户万能DIY商城系统源码,搭建简单。 以下是部分代码示…...
Qt 6之七:学习资源
Qt 6之七:学习资源 Qt是一种跨平台的C应用程序开发框架,它提供了一套丰富的工具和库,可以帮助开发者快速构建跨平台的应用程序,用于开发图形用户界面(GUI)和非GUI应用程序。 Qt 6之一:简介、安…...
解决大模型的幻觉问题:一种全新的视角
在人工智能领域,大模型已经成为了一个重要的研究方向。然而,随着模型规模的不断扩大,一种新的问题开始浮出水面,那就是“幻觉”问题。这种问题的出现,不仅影响了模型的性能,也对人工智能的发展带来了新的挑…...
mysql进阶-重构表
目录 1. 原因 2. 如何重构表呢? 2.1 命令1: 2.2 命令2: 2.3 命令3: 1. 原因 正常的业务开发,为什么需要重构表呢? 原因1:某张表存在大量的新增和删除操作,导致表经历过大量的…...
Element-ui图片懒加载
核心代码 <el-image src"https://img-blog.csdnimg.cn/direct/2236deb5c315474884599d90a85d761d.png" alt"我是图片" lazy><img slot"error" src"https://img-blog.csdnimg.cn/direct/81bf096a0dff4e5fa58e5f43fd44dcc6.png&quo…...
Linux系统——DNS解析详解
目录 一、DNS域名解析 1.DNS的作用 2.域名的组成 2.1域名层级结构关系特点 2.2域名空间构成 2.3域名的四种不同类型 2.3.1延伸 2.3.2总结 3.DNS域名解析过程 3.1递归查询 3.2迭代查询 3.3一次DNS解析的过程 4.DNS系统类型 4.1缓存域名服务器 4.2主域名服务器 4…...
初识Ubuntu
其实还是linux操作系统 命令都一样 但是在学习初级阶段,我还是将其分开有便于我的学习和稳固。 cat 查看文件 命令 Ubuntu工作中经常是用普通用户,在需要时才进行登录管理员用户 sudn -i 切换成管理用户 我们远程连接时 如果出现 hostname -I没有出现…...
Casper Network (CSPR)2024 年愿景:通过投资促进增长
Casper Network (CSPR)是行业领先的 Layer-1 区块链网络之一,通过推出了一系列值得关注的技术改进和倡议,已经为 2024 年做好了准备。 在过去的一年里,Casper Network (CSPR)不断取得里程碑式的进展,例如推…...
《MySQL系列-InnoDB引擎06》MySQL锁介绍
文章目录 第六章 锁1 什么是锁2 lock与latch3 InnoDB存储引擎中的锁3.1 锁的类型3.2 一致性非锁定读3.3 一致性锁定读3.4 自增长与锁3.5 外键和锁 4 锁的算法4.1 行锁的三种算法4.2 解决Phantom Problem 5 锁问题5.1 脏读5.2 不可重复读5.3 丢失更新 6 阻塞7 死锁 第六章 锁 开…...
获取多个PDF文件的内容并保存到excel上
# shuang # 开发时间:2023/12/9 22:03import pdfplumber import re import os import pandas as pd import datetimedef re_text(bt, text):# re 搜索正则匹配 包含re.compile包含的文字内容m1 re.search(bt, text)if m1 is not None:return re_block(m1[0])return…...
深入了解网络流量清洗--使用免费的雷池社区版进行防护
随着网络攻击日益复杂,企业面临的网络安全挑战也在不断增加。在这个背景下,网络流量清洗成为了确保企业网络安全的关键技术。本文将探讨雷池社区版如何通过网络流量清洗技术,帮助企业有效应对网络威胁。 ![] 网络流量清洗的重要性&#x…...
【FFMPEG应用篇】基于FFmpeg的转码应用(FLV MP4)
方法声明 extern "C" //ffmpeg使用c语言实现的,引入用c写的代码就要用extern { #include <libavcodec/avcodec.h> //注册 #include <libavdevice/avdevice.h> //设备 #include <libavformat/avformat.h> #include <libavutil/…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
