Springboot使用ThreadPoolTaskScheduler轻量级多线程定时任务框架

embedded/2024/9/25 13:59:02/

简介: Spring注解定时任务使用不是很灵活,如果想要灵活的配置定时任务,可以使用xxl-job 或者 quartz等定时任务框架,但是过于繁琐,可能成本较大。所以可以使用ThreadPoolTaskScheduler来灵活处理定时任务

ThreadPoolTaskScheduler是什么

ThreadPoolTaskScheduler 是 Spring Framework 中的一部分,主要用于调度任务。它基于线程池,可以处理异步任务和定时任务

主要api

  • schedule(Runnable task, Trigger trigger) corn表达式,周期执行
  • schedule(Runnable task, Date startTime) 定时执行
  • scheduleAtFixedRate(Runnable task, Date startTime, long period)
    定时周期间隔时间执行。间隔时间单位 TimeUnit.MILLISECONDS
  • scheduleAtFixedRate(Runnable task, long period) 间隔时间以固定速率执行。单位毫秒

固定速率执行不会管上次执行的状态如何

在使用前需要配置下ThreadPoolTaskScheduler

java">@Configuration
public class SchedulingTaskConfig {@Bean(name = "myThreadPoolTaskScheduler")public ThreadPoolTaskScheduler threadPoolTaskScheduler(){ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();taskScheduler.setPoolSize(60);taskScheduler.setThreadNamePrefix("task-");taskScheduler.setAwaitTerminationSeconds(3000);taskScheduler.setWaitForTasksToCompleteOnShutdown(true);return taskScheduler;}
}

cron表达式

java">@Overridepublic String startTask() {ScheduledFuture<?> schedule = myThreadPoolTaskScheduler.schedule(new Runnable() {@Overridepublic void run() {System.out.println("1s执行一次");}}, new CronTrigger("0/1 * * * * ?"));

定时执行一次

java"> myThreadPoolTaskScheduler.schedule(new Runnable() {@Overridepublic void run() {System.out.println("定时执行3s后开始执行");}},new Date(System.currentTimeMillis() + 3000));

在固定时间以固定速率执行

java"> myThreadPoolTaskScheduler.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {System.out.println("定时执行3s后开始执行,固定3s执行一次");}},new Date(System.currentTimeMillis() + 3000),3000);

任务取消

java">private  ScheduledFuture<?> schedule ;@Overridepublic String startTask() {schedule = myThreadPoolTaskScheduler.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {System.out.println("定时执行3s后开始执行,固定3s执行一次");}}, new Date(System.currentTimeMillis() + 3000), 3000);return "开启成功";}@Overridepublic String stopTask() {if (schedule != null){schedule.cancel(true);System.out.println("任务取消成功");return "取消成功";}return "取消失败";}

实现页面控制定时任务开关

将定时任务保存到数据库中,并在页面上实现定时任务的开关,以及更新定时任务时间后重新创建定时任务

数据库实体

java">@TableName("task")
@Data
public class ScheduleTask {public interface Update{};@TableId(type = IdType.AUTO)@NotNull(message = "任务id不能为空",groups = Update.class)private Integer id;@NotBlank(message = "请填写任务执行类")@TableField("task_clazz")private String taskClazz;@NotBlank(message = "请填写任务执行方法")@TableField("task_method")private String taskMethod;@NotBlank(message = "请填写任务执行时间,采用cron格式")@TableField("cron")private String cron;@TableLogic@TableField("status")private Integer status;
}

contrloller

java">@RestController
@RequiredArgsConstructor
public class TaskManagerController {private final TaskManagerService taskManagerService;@PostMapping("/addTask")public Boolean addTask(@RequestBody @Validated ScheduleTask task){return taskManagerService.addTask(task);}@PostMapping("/stopTask/{id}")public Boolean stopTask(@PathVariable Integer id){return taskManagerService.stopTask(id);}
}

service

java">@Service
@Slf4j
@RequiredArgsConstructor
public class TaskManagerServiceImpl implements TaskManagerService {private final ScheduleTaskMapper scheduleTaskMapper;private final TaskManager taskManager;@Overridepublic Boolean addTask(ScheduleTask task) {int i = scheduleTaskMapper.insert(task);if (i > 0){TaskRunnable taskRunnable = new TaskRunnable(task.getTaskClazz(), task.getTaskMethod());taskManager.addTask(String.valueOf(task.getId()),taskRunnable,task.getCron());return true;}return false;}@Overridepublic Boolean stopTask(Integer id) {int i = scheduleTaskMapper.deleteById(id);if (i> 0){taskManager.stopTask(String.valueOf(id));return true;}return false;}
}

TaskRunnable

通过此类获取具体的执行方法

java">@Slf4j
public class TaskRunnable implements Runnable{/*** 定时任务类*/private final String clazz;/*** 定时任务方法*/private final String methodName;public TaskRunnable(String clazz, String methodName) {this.clazz = clazz;this.methodName = methodName;}@Overridepublic void run() {try {//获取类Object bean = SpringContextUtils.getBean(clazz);//获取方法Method method = bean.getClass().getDeclaredMethod(methodName);//设置方法可用ReflectionUtils.makeAccessible(method);//执行方法method.invoke(bean);} catch (Exception e) {log.error("获取方法信息报错:{}",e.getMessage());throw new RuntimeException(e);}}
}

任务调度类

java">@Component
@RequiredArgsConstructor
@Slf4j
public class TaskManager {private final ThreadPoolTaskScheduler myThreadPoolTaskScheduler;public static ConcurrentHashMap<String, ScheduledFuture<?>> cache = new ConcurrentHashMap<>();/*** 创建定时任务* @param key 任务key* @param taskRunnable 当前线程* @param cron 定时任务cron*/public void addTask(String key ,TaskRunnable taskRunnable ,String cron){//取消任务this.stopTask(key);ScheduledFuture<?> schedule = myThreadPoolTaskScheduler.schedule(taskRunnable, new CronTrigger(cron));if (schedule != null){cache.put(key,schedule);log.info("当key为{}的定时任务创建成功",key);}}public void stopTask(String key){if (cache.get(key) == null){log.info("当前没有key为{}的定时任务",key);return;}ScheduledFuture<?> scheduledFuture = cache.get(key);if (scheduledFuture != null){scheduledFuture.cancel(true);cache.remove(key);log.info("当前key为{}的定时任务已取消",key);}}
}

工具类

java">@Component
public class SpringContextUtils implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {SpringContextUtils.context = applicationContext;}public static Object getBean(String name){return context.getBean(name);}
}

方法测试

java">
@Slf4j
@Component(value = "testTask")
public class TestTask {public void taskMethod(){log.info(String.format("调用了当前定时任务"));}
}


http://www.ppmy.cn/embedded/116639.html

相关文章

Python中字典常用方法

# 定义字典: # 定义一个空字典 my_dict {}# 定义一个包含不同类型键值对的字典 my_dict {name: John, age: 30, 1: a, 2: b, 3: c} print(my_dict) # 输出&#xff1a;{name: John, age: 30, 1: a, 2: b, 3: c}# 定义一个嵌套字典&#xff08;字典中包含字典&#xff09; my…

C语言指针简介篇

1. 指针的基本概念 什么是指针&#xff1a; 指针是一个变量&#xff0c;用于存储另一个变量的内存地址。通过指针&#xff0c;程序可以直接访问和操作存储在内存中的数据。 指针与变量的关系&#xff1a; 在C语言中&#xff0c;每个变量都有一个地址&#xff0c;可以使用&运…

【Linux网络 —— 网络基础概念】

Linux网络 —— 网络基础概念 计算机网络背景网络发展 初始协议协议分层协议分层的好处 OSI七层模型TCP/IP五层(或四层)模型 再识协议为什么要有TCP/IP协议&#xff1f;什么是TCP/IP协议&#xff1f;TCP/IP协议与操作系统的关系所以究竟什么是协议&#xff1f; 网络传输基本流程…

灵当CRM系统index.php存在SQL注入漏洞

文章目录 免责申明漏洞描述搜索语法漏洞复现nuclei修复建议 免责申明 本文章仅供学习与交流&#xff0c;请勿用于非法用途&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任 漏洞描述 灵当CRM系统是一款功能全面、易于使用的客户关系管理&#xff08;C…

基于pdf.js实现对pdf预览、批注功能、 保存下载pdf,适配H5,平板 踩坑记录

项目场景&#xff1a; 在APP端实现对pdf的批注,能够下载保存.能够获取批注信息同时能够重新渲染到pdf中.基于pdf.js-4.5.136版本源码实现。pc端能够正常预览下载pdf&#xff0c;构建打包后嵌入uniapp的webview遇到的问题记录 问题描述 将构建打包后的代码嵌入到uniapp中&…

WPF入门教学八 Canvas与WrapPanel的使用

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;Canvas和WrapPanel是两种常用的布局容器。Canvas允许你在其内部自由地定位子元素&#xff0c;而WrapPanel则会根据可用空间自动排列子元素。下面是一个简单的入门教学&#xff0c;介绍如何在WPF中使…

解决pandas DataFrame创建时的长度不一致问题之ValueError: All arrays must be of the same length

在使用pandas库创建DataFrame时&#xff0c;一个常见的错误是遇到 "ValueError: All arrays must be of the same length" 信息。这个错误的提示是我们在尝试构建DataFrame时&#xff0c;提供给构造函数 的各个数组&#xff08;或列表&#xff09;的长度不匹配。下…

外网SpringBoot项目迁移到内网无法加载maven依赖

外网SpringBoot项目迁移到内网无法加载maven依赖 **问题&#xff1a;**把外网项目拷贝到内网&#xff0c;并且把仓库下载好的依赖包放到内网&#xff0c;内网打开项目后全部飘红。 **原因&#xff1a;**拷贝过来的仓库依赖中含有_remote.repositories文件&#xff0c;加载时默…