Spring Boot 动态定时任务管理系统(轻量级实现)

news/2024/12/27 12:24:28/

Spring Boot项目中,实现动态增删和启停定时任务的功能对于许多应用场景来说至关重要。虽然Quartz框架是一个广泛使用的解决方案,但其复杂性和重量级特性可能使得项目变得臃肿和难以维护。为了解决这个问题,本项目旨在实现一个轻量级的定时任务管理系统,不依赖外部框架,仅利用Spring Boot和Java标准库的功能,特别适用于单体项目。

数据库

DROP TABLE IF EXISTS `scheduled_jobs`;
CREATE TABLE `scheduled_jobs`  (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '任务ID,唯一标识每个定时任务',`method_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '方法名称,执行定时任务时调用的方法名',`cron_expression` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'cron表达式,定义定时任务的执行时间规则',`status` int(11) NOT NULL DEFAULT 1 COMMENT '任务状态,1为正常运行,0为暂停',`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '任务正文,具体需要执行的内筒',`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '任务的备注信息,描述任务的其他细节',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间,自动设置为当前时间',`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务最后更新时间,每次更新时自动更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1391804419 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

POM依赖

  <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.9</version></dependency><!--lombok依赖--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--MySQL数据库的依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!--hutool工具依赖--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.26</version></dependency>

项目启动类

java">import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.sws.dynamicscheduler.mapper")
public class DynamicSchedulerApplication {public static void main(String[] args) {SpringApplication.run(DynamicSchedulerApplication.class, args);}}

任务管理器类

java">import com.sws.dynamicscheduler.mapper.ScheduledJobMapper;
import com.sws.dynamicscheduler.model.ScheduledJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ScheduledFuture;@Service
@Slf4j
public class DynamicTaskManager {private final ThreadPoolTaskScheduler taskScheduler;private final ScheduledJobMapper scheduledJobMapper;private final Map<String, ScheduledFuture<?>> scheduledTasks;@Autowiredpublic DynamicTaskManager(ScheduledJobMapper scheduledJobMapper, ThreadPoolTaskScheduler taskScheduler) {this.scheduledJobMapper = scheduledJobMapper;this.taskScheduler = taskScheduler;this.scheduledTasks = new HashMap<>();}@PostConstructpublic void init() {// 初始化时加载数据库中的所有定时任务并调度List<ScheduledJob> jobs = scheduledJobMapper.selectList(null);for (ScheduledJob job : jobs) {if (job.getStatus() == 1) {addTask(job.getCronExpression(), job.getMethodName(),job.getContent(), job.getId().toString());}}}// 动态新增任务public String addTask(String cronExpression, String methodName, String content,String taskId) {Runnable task = () -> {// 执行定时任务的逻辑log.info("执行了定时任务:{},执行内容是:{}",methodName,content);};ScheduledFuture<?> scheduledFuture = taskScheduler.schedule(task, new CronTrigger(cronExpression));scheduledTasks.put(taskId, scheduledFuture);return taskId;}// 动态删除任务public void removeTask(String taskId) {ScheduledFuture<?> scheduledFuture = scheduledTasks.get(taskId);if (scheduledFuture != null) {scheduledFuture.cancel(false); // 取消任务scheduledTasks.remove(taskId); // 从集合中删除}}// 停止任务public void stopTask(Integer jobId) {Optional<ScheduledJob> jobOptional = Optional.ofNullable(scheduledJobMapper.selectById(jobId));jobOptional.ifPresent(job -> {job.setStatus(0); // 设置为暂停状态scheduledJobMapper.insert(job);removeTask(jobId.toString()); // 停止定时任务});}// 恢复任务public void resumeTask(Integer jobId) {Optional<ScheduledJob> jobOptional = Optional.ofNullable(scheduledJobMapper.selectById(jobId));jobOptional.ifPresent(job -> {job.setStatus(1); // 设置为正常状态scheduledJobMapper.insert(job);addTask(job.getCronExpression(), job.getMethodName(), job.getContent(),jobId.toString()); // 恢复定时任务});}
}

实体类

java">import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.util.Date;@Data
@TableName("`scheduled_jobs`")
public class ScheduledJob {private Integer id;                // 任务ID,唯一标识每个定时任务private String methodName;         // 方法名称,执行定时任务时调用的方法名private String cronExpression;    // cron表达式,定义定时任务的执行时间规则private Integer status;            // 任务状态,1为正常运行,0为暂停private String content;           // 任务正文,具体需要执行的内容private String remark;             // 任务的备注信息,描述任务的其他细节private Date createTime;           // 任务创建时间,自动设置为当前时间private Date updateTime;           // 任务最后更新时间,每次更新时自动更新时间}

配置类

java">import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;@Configuration
public class SchedulerConfig {@Beanpublic ThreadPoolTaskScheduler taskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(10); // 设置线程池的大小scheduler.setThreadNamePrefix("scheduled-task-"); // 设置线程名称前缀return scheduler;}
}

Mapper类

java">import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sws.dynamicscheduler.model.ScheduledJob;public interface ScheduledJobMapper extends BaseMapper<ScheduledJob> {}

控制类

java">import com.sws.dynamicscheduler.model.ScheduledJob;
import com.sws.dynamicscheduler.mapper.ScheduledJobMapper;
import com.sws.dynamicscheduler.scheduler.DynamicTaskManager;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.List;@RestController
@RequestMapping("/tasks")
public class TaskController {@ResourceDynamicTaskManager taskManager;@ResourceScheduledJobMapper scheduledJobMapper;// 动态添加任务@PostMapping("/add")public String addTask(@RequestParam String cronExpression, @RequestParam String methodName,@RequestParam String content) {ScheduledJob job = new ScheduledJob();job.setMethodName(methodName);job.setContent(content);job.setCronExpression(cronExpression);job.setStatus(1);scheduledJobMapper.insert(job); // 保存到数据库// 添加定时任务return taskManager.addTask(cronExpression, methodName,content,job.getId().toString());}// 动态删除任务@DeleteMapping("/remove")public void removeTask(@RequestParam Integer jobId) {taskManager.removeTask(jobId.toString());scheduledJobMapper.deleteById(jobId);}// 暂停任务@PostMapping("/pause")public void pauseTask(@RequestParam Integer jobId) {taskManager.stopTask(jobId);}// 恢复任务@PostMapping("/resume")public void resumeTask(@RequestParam Integer jobId) {taskManager.resumeTask(jobId);}// 获取所有任务@GetMapping("/all")public List<ScheduledJob> getAllTasks() {return scheduledJobMapper.selectList(null);}
}

项目地址:神蛐/DynamicScheduler


http://www.ppmy.cn/news/1558522.html

相关文章

imgproxy图像处理的高效与安全

摘要 imgproxy作为一个高效且安全的独立服务器,为图像处理提供了全新的解决方案。它不仅简化了图像调整和转换的过程,还极大地提升了处理速度,确保了整个流程的安全性。通过集成imgproxy,用户可以轻松优化网页上的图像,提高加载速度,改善用户体验。本文将深入探讨imgpro…

sed正则表达式元字符 和使用示例 sed变量替换示例

在使用 sed进行查找替换是我们也是可以使用正则表达式的&#xff0c; 不过sed默认只能使用基础正则表达式&#xff0c; ? 和 <> 和()分组等这些扩展正则表达式在sed里面默认是不能用的。 sed支持的正则元字符如下&#xff1a; 元字符 作用 * 前一个字符匹配0次或…

Blender高效优化工作流程快捷小功能插件 Haggis Tools V1.1.5

Haggis Tools V1.1.5 是一款专为Blender设计的插件&#xff0c;旨在优化工作流程、减少单调和重复的任务&#xff0c;从而为艺术家节省时间。这款插件适用于多个版本的Blender&#xff0c;能够有效提升工作效率。 Blender插件特点&#xff1a; 工作流程优化&#xff1a;专门设…

天池工业蒸汽量预测教程

一、引言 在现代工业生产中&#xff0c;蒸汽作为一种重要的能源载体&#xff0c;广泛应用于化工、制药、纺织、食品加工等众多领域。准确预测工业蒸汽量对于优化生产流程、提高能源利用效率、降低成本以及保障生产的稳定性具有至关重要的意义。天池举办的工业蒸汽量预测赛事&a…

穿山甲等广告联盟依据哪些维度给APP、小程序结算广告变现收益

媒体在开展广告变现商业化时&#xff0c;最关心的是变现收益问题&#xff0c;所运营的不同体量的APP、小程序能产生多少广告变现收益。#广告联盟# 广告变现的价格、收益不是一成不变的&#xff0c;广告转化是影响广告收益的重要因素之一。广告平台针对整个变现链路上的各环节&…

WebSocket | 背景 概念 原理 使用 优缺点及适用场景

1 背景 在 WebSocket 出现之前&#xff0c;为了实现推送技术&#xff0c;所用的技术都是轮询&#xff0c;轮询是指浏览器每隔一段时间向服务器发出 HTTP 请求&#xff0c;服务器再返回最新的数据给客户端 常见的轮询方式分为轮询与长轮询&#xff0c;它们的区别如下图所示&…

餐厅下单助手系统(Java+MySQL)

项目概览 餐厅下单助手系统是一个采用 Java 实现的小型食品订单管理系统&#xff0c;并且以 SwingUI 打造视觉界面&#xff0c;数据库提供。本系统分为商家和顾客两类体验&#xff0c;有效地给予简洁性能。可用做课程设计&#xff0c;参考学习。 技术栈 Java: 核心开发语言S…

【Vue3+ts入门小试牛刀】

Vue 3是一个流行的JavaScript框架&#xff0c;它提供了创建交互式用户界面的工具。Vite是一个现代化的构建工具&#xff0c;用于快速构建Vue应用。TypeScript是一种类型安全的JavaScript的超集&#xff0c;它可以帮助我们在开发过程中减少错误。 下面是一个使用Vue 3、Vite和T…