动态定时任务ThreadPoolTaskScheduler

2024-02-27 07:36

本文主要是介绍动态定时任务ThreadPoolTaskScheduler,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在工作中出现了这样一个需求,用户可以制定多个任务,每个任务可以定时分配给多个人。任务的属性包括:任务巡检周期、任务工作日历、巡检人员。
这就需要我们开发一个动态的定时任务功能,而且这个定时任务是可以随时新增、更改、停止的。刚开始接到这个需求的时候我就直接说,我一两天开发不完QwQ,但其实这个功能一点也不难,只是我不知道还有ThreadPoolTaskScheduler这种简便的开发工具罢了,自己菜怨不得需求难。
但是一开始还是走了一些弯路的:
package cn.dxsc.safety.web.config;import cn.dxsc.safety.common.util.ChinaHolidaysUtils;
import cn.dxsc.safety.common.util.StreamUtils;
import cn.dxsc.safety.common.util.StringUtils;
import cn.dxsc.safety.dao.mapper.TaskDistributionMapper;
import cn.dxsc.safety.dao.mapper.TroubleCheckTaskDistributionMapper;
import cn.dxsc.safety.entity.po.TaskDistribution;
import cn.dxsc.safety.entity.po.TroubleCheckTaskDistribution;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;@Component
public class AutoDistributionTask implements SchedulingConfigurer {//这里有一些是我的业务代码,没有删@Autowiredprivate TroubleCheckTaskDistributionMapper troubleCheckTaskDistributionMapper;@Autowiredprivate TaskDistributionMapper taskDistributionMapper;private List<TroubleCheckTaskDistribution> troubleCheckTaskDistributions;/*** 初始化时调用* 目的:为动态定时任务赋予初始值*/@PostConstructpublic void doConstruct() {this.troubleCheckTaskDistributions = troubleCheckTaskDistributionMapper.selectList(null);}@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {for (TroubleCheckTaskDistribution troubleCheckTaskDistribution : troubleCheckTaskDistributions) {//第一个动态定时任务// 动态使用cron表达式设置循环间隔taskRegistrar.addTriggerTask(() -> System.out.println("Current time: " + DateUtil.now()), triggerContext -> {// 使用CronTrigger触发器,可动态修改cron表达式来操作循环规则CronTrigger cronTrigger = new CronTrigger(troubleCheckTaskDistribution.getCron());
//                //--------此处替换执行操作
//                String workType = troubleCheckTaskDistribution.getWorkType();
//                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//                boolean publicHolidays = false;
//                try {
//                    publicHolidays = ChinaHolidaysUtils.isPublicHolidays(simpleDateFormat.format(new Date()));
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//                //判断工作日类型
//                if(new Date().after(troubleCheckTaskDistribution.getBeginTime()) && !StringUtils.isEmpty(workType))
//                    if ((workType.equals("法定工作日") && publicHolidays)||(workType.equals("非法定工作日") && !publicHolidays)||workType.equals("每天")){
//                        List<TaskDistribution> taskDistributions = taskDistributionMapper.selectList(new LambdaQueryWrapper<TaskDistribution>().eq(TaskDistribution::getTroubleCheckTaskDistributionId, troubleCheckTaskDistribution.getId()))
//                                .stream().filter(StreamUtils.distinctByKey(TaskDistribution::getCheckPeople)).collect(Collectors.toList());
//                        if(taskDistributions.size() != 0){
//                            TaskDistribution taskDistribution = new TaskDistribution();
//                            taskDistribution.setBeginTime(new Date());
//                            taskDistribution.setTroubleCheckTaskDistributionId(troubleCheckTaskDistribution.getId());
//                            taskDistribution.setCheckCompany(taskDistributions.get(0).getCheckCompany());
//                            taskDistributionMapper.insert(taskDistribution);
//                        }
//                    }return cronTrigger.nextExecutionTime(triggerContext);});}}
}
一开始百度到了这样一个方法,可以为动态定时任务赋予初始值,在doConstruct()里获取到了当前数据库里所有的任务的,然后加入到taskRegistrar里面去执行,获取每个任务生成的cron表达式,然后处理业务巴拉巴拉。然后系统一部署后我就不能在新增、修改、删除定时任务了,这怎么能行。
马上,第二种方法:

1、首先创建配置类

package cn.dxsc.safety.common.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;/*** @author mrChen* @date 2024/2/23 9:16*/
@Configuration
public class ThreadPoolConfig {public static ConcurrentHashMap<String, ScheduledFuture> cache = new ConcurrentHashMap<String, ScheduledFuture>();@Beanpublic ThreadPoolTaskScheduler threadPoolTaskScheduler() {ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();threadPoolTaskScheduler.setPoolSize(100);threadPoolTaskScheduler.setThreadNamePrefix("taskExecutor-");threadPoolTaskScheduler.setAwaitTerminationSeconds(10);threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);return threadPoolTaskScheduler;}
}

2、然后是一个任务添加、删除的统一处理

package cn.dxsc.safety.web.config;import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.stereotype.Component;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;/*** @author mrChen* @date 2024/2/22 21:39*/
@Component
public class CronTask {finalThreadPoolTaskScheduler threadPoolTaskScheduler;private Map<String, ScheduledFuture<?>> taskFutures = new ConcurrentHashMap<String, ScheduledFuture<?>>();public CronTask(ThreadPoolTaskScheduler threadPoolTaskScheduler) {this.threadPoolTaskScheduler = threadPoolTaskScheduler;}/*** 添加任务** @param taskId* @param triggerTask*/public void addTriggerTask(String taskId, TriggerTask triggerTask) {if (taskFutures.containsKey(taskId)) {throw new SchedulingException("the taskId[" + taskId + "] was added.");}ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(triggerTask.getRunnable(), triggerTask.getTrigger());taskFutures.put(taskId, schedule);}/*** 取消任务** @param taskId*/public void cancelTriggerTask(String taskId) {ScheduledFuture<?> future = taskFutures.get(taskId);if (future != null) {future.cancel(true);}taskFutures.remove(taskId);}
}

3、最后是我的业务代码

@PutMapping("/update")@ApiOperation("根据主键修改")public R update(@RequestBody TroubleCheckTaskDistributionDto dto) {TroubleCheckTaskDistribution h=new TroubleCheckTaskDistribution();BeanUtils.copyProperties(dto, h);String inspCycle = dto.getInspCycle();String inspUnit = dto.getInspUnit();Date beginTime = dto.getBeginTime();int year = beginTime.getYear();int month = beginTime.getMonth() + 1;int day = beginTime.getDay() + 4;int hours = beginTime.getHours();int minutes = beginTime.getMinutes();int seconds = beginTime.getSeconds();//生成cronString cron = "";switch (inspUnit) {case "小时":cron = seconds+" "+minutes+" 0/" + inspCycle + " * * ?";break;case "天":cron = seconds+" "+minutes+" "+hours+" */"+inspCycle+" * ?";//在这个表达式中,“001"表示任务每天的凌晨1点开始执行,"*/3"表示任务每隔三天执行一次,“*"表示任何月份都可以执行,“?”表示不考虑星期几的条件。break;case "月":cron = seconds+" "+minutes+" "+hours+" "+day +" "+"1/"+inspCycle+" ?";break;case "年":cron = seconds+" "+minutes+" "+hours+" "+day+" "+month+" ?";break;}h.setCron(cron);boolean b = iTroubleCheckTaskDistributionService.updateById(h);if (taskHashMap.size() >= 50){return R.fail("所设置的任务已经超标!");}if(this.taskHashMap.containsKey(h.getId())) {cronTask.cancelTriggerTask(String.valueOf(h.getId()));taskHashMap.remove(h.getId());}this.taskHashMap.put(h.getId(), cron);TriggerTask triggerTask = new TriggerTask(new Runnable() {@Overridepublic void run() {System.out.println("Current time: " + DateUtil.now() + "执行任务:" + h.getId());//--------此处替换执行操作String workType = h.getWorkType();SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");boolean publicHolidays = false;try {publicHolidays = ChinaHolidaysUtils.isPublicHolidays(simpleDateFormat.format(new Date()));} catch (IOException e) {e.printStackTrace();}//判断工作日类型if (new Date().after(h.getBeginTime()) && !StringUtils.isEmpty(workType))if ((workType.equals("法定工作日") && publicHolidays) || (workType.equals("非法定工作日") && !publicHolidays) || workType.equals("每天")) {
//                                List<TaskDistribution> taskDistributions = taskDistributionMapper.selectList(new LambdaQueryWrapper<TaskDistribution>().eq(TaskDistribution::getTroubleCheckTaskDistributionId, h.getId()))
//                                        .stream().filter(StreamUtils.distinctByKey(TaskDistribution::getCheckPeople)).collect(Collectors.toList());List<TaskDistribution> taskDistributions = dto.getTaskDistributions();if (taskDistributions.size() != 0) {for (TaskDistribution taskDistribution : taskDistributions) {taskDistribution.setBeginTime(new Date());taskDistribution.setId(null);taskDistributionMapper.insert(taskDistribution);}}}}},new CronTrigger(this.taskHashMap.get(h.getId())));cronTask.addTriggerTask(String.valueOf(h.getId()), triggerTask);return b ? R.ok() : R.fail();}

一个集坚强与信心于一身的菇凉。

这篇关于动态定时任务ThreadPoolTaskScheduler的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/751658

相关文章

基于Canvas的Html5多时区动态时钟实战代码

《基于Canvas的Html5多时区动态时钟实战代码》:本文主要介绍了如何使用Canvas在HTML5上实现一个多时区动态时钟的web展示,通过Canvas的API,可以绘制出6个不同城市的时钟,并且这些时钟可以动态转动,每个时钟上都会标注出对应的24小时制时间,详细内容请阅读本文,希望能对你有所帮助...

Vue中动态权限到按钮的完整实现方案详解

《Vue中动态权限到按钮的完整实现方案详解》这篇文章主要为大家详细介绍了Vue如何在现有方案的基础上加入对路由的增、删、改、查权限控制,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、数据库设计扩展1.1 修改路由表(routes)1.2 修改角色与路由权限表(role_routes)二、后端接口设计

前端 CSS 动态设置样式::class、:style 等技巧(推荐)

《前端CSS动态设置样式::class、:style等技巧(推荐)》:本文主要介绍了Vue.js中动态绑定类名和内联样式的两种方法:对象语法和数组语法,通过对象语法,可以根据条件动态切换类名或样式;通过数组语法,可以同时绑定多个类名或样式,此外,还可以结合计算属性来生成复杂的类名或样式对象,详细内容请阅读本文,希望能对你有所帮助...

Nginx实现动态封禁IP的步骤指南

《Nginx实现动态封禁IP的步骤指南》在日常的生产环境中,网站可能会遭遇恶意请求、DDoS攻击或其他有害的访问行为,为了应对这些情况,动态封禁IP是一项十分重要的安全策略,本篇博客将介绍如何通过NG... 目录1、简述2、实现方式3、使用 fail2ban 动态封禁3.1 安装 fail2ban3.2 配

Vue3中的动态组件详解

《Vue3中的动态组件详解》本文介绍了Vue3中的动态组件,通过`component:is=动态组件名或组件对象/component`来实现根据条件动态渲染不同的组件,此外,还提到了使用`markRa... 目录vue3动态组件动态组件的基本使用第一种写法第二种写法性能优化解决方法总结Vue3动态组件动态

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Java使用POI-TL和JFreeChart动态生成Word报告

《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码... 目录前言一、需求背景二、方案分析三、 POI-TL + JFreeChart 实现3.1 Maven

Java导出Excel动态表头的示例详解

《Java导出Excel动态表头的示例详解》这篇文章主要为大家详细介绍了Java导出Excel动态表头的相关知识,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录前言一、效果展示二、代码实现1.固定头实体类2.动态头实现3.导出动态头前言本文只记录大致思路以及做法,代码不进

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

《SpringBoot整合ShedLock处理定时任务重复执行的问题小结》ShedLock是解决分布式系统中定时任务重复执行问题的Java库,通过在数据库中加锁,确保只有一个节点在指定时间执行... 目录前言什么是 ShedLock?ShedLock 的工作原理:定时任务重复执行China编程的问题使用 Shed

vue基于ElementUI动态设置表格高度的3种方法

《vue基于ElementUI动态设置表格高度的3种方法》ElementUI+vue动态设置表格高度的几种方法,抛砖引玉,还有其它方法动态设置表格高度,大家可以开动脑筋... 方法一、css + js的形式这个方法需要在表格外层设置一个div,原理是将表格的高度设置成外层div的高度,所以外层的div需要