RuoYi模块功能分析:第八章定时任务

2024-02-10 23:28

本文主要是介绍RuoYi模块功能分析:第八章定时任务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

系列文章目录

文章目录

  • 系列文章目录
  • 引入依赖
  • 一、AbstractQuartzJob类
  • 二、QuartzJobExecution类
  • 三、QuartzDisallowConcurrentExecution类
  • 四、JobInvokeUtil类
  • 五、CronUtils类
  • 六、ScheduleUtils类


引入依赖

<!-- 定时任务 -->
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><exclusions><exclusion><groupId>com.mchange</groupId><artifactId>c3p0</artifactId></exclusion></exclusions>
</dependency>

一、AbstractQuartzJob类

改类位于package com.ruoyi.quartz.util;目录下。主要用于记录日志和定义执行任务是否支持并发执行的抽象方法

/*** 抽象quartz调用** @author ruoyi*/
public abstract class AbstractQuartzJob implements Job
{private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);/*** 线程本地变量*/private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException{// 创建任务对象SysJob sysJob = new SysJob();BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));try{// 任务执行前before(context, sysJob);if (sysJob != null){// 执行任务doExecute(context, sysJob);}// 任务执行后after(context, sysJob, null);}catch (Exception e){log.error("任务执行异常  - :", e);// 记录日志after(context, sysJob, e);}}/*** 执行前,记录当前系统时间** @param context 工作执行上下文对象* @param sysJob 系统计划任务*/protected void before(JobExecutionContext context, SysJob sysJob){threadLocal.set(new Date());}/*** 执行后,记录执行后日志** @param context 工作执行上下文对象* @param sysJob 系统计划任务*/protected void after(JobExecutionContext context, SysJob sysJob, Exception e){// 获取开始时间Date startTime = threadLocal.get();// 清除本次线程数据threadLocal.remove();// 设置任务日志final SysJobLog sysJobLog = new SysJobLog();sysJobLog.setJobName(sysJob.getJobName());sysJobLog.setJobGroup(sysJob.getJobGroup());sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());sysJobLog.setStartTime(startTime);sysJobLog.setStopTime(new Date());long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");if (e != null){sysJobLog.setStatus(Constants.FAIL);// 获取并设置异常详细信息String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);sysJobLog.setExceptionInfo(errorMsg);}else{sysJobLog.setStatus(Constants.SUCCESS);}// 写入数据库当中SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);}/*** 执行方法,由子类重载** @param context 工作执行上下文对象* @param sysJob 系统计划任务* @throws Exception 执行过程中的异常*/protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
}

二、QuartzJobExecution类

继承了AbstractQuartzJob,支持并发执行。位于package com.ruoyi.quartz.util;包下

/*** 定时任务处理(允许并发执行)* * @author ruoyi**/
public class QuartzJobExecution extends AbstractQuartzJob
{@Overrideprotected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception{// 执行目标方法JobInvokeUtil.invokeMethod(sysJob);}
}

三、QuartzDisallowConcurrentExecution类

继承了AbstractQuartzJob,不支持并发执行。位于package com.ruoyi.quartz.util;包下

/*** 定时任务处理(禁止并发执行)* * @author ruoyi**/
@DisallowConcurrentExecution
public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
{@Overrideprotected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception{// 执行目标方法JobInvokeUtil.invokeMethod(sysJob);}
}

四、JobInvokeUtil类

该类主要用于获取执行目标的相关信息并且根据有无参数执行目标方法。位于package com.ruoyi.quartz.util;包下

/*** 任务执行工具** @author ruoyi*/
public class JobInvokeUtil
{/*** 执行方法** @param sysJob 系统任务*/public static void invokeMethod(SysJob sysJob) throws Exception{// 获取目标字符串String invokeTarget = sysJob.getInvokeTarget();// 获取bean名称String beanName = getBeanName(invokeTarget);// 获取方法名String methodName = getMethodName(invokeTarget);// 获取参数列表List<Object[]> methodParams = getMethodParams(invokeTarget);// 判断class名是否存在if (!isValidClassName(beanName)){// 不存在,直接获取bean对象Object bean = SpringUtils.getBean(beanName);invokeMethod(bean, methodName, methodParams);}else{// 存在,动态地根据一个类名加载并实例化一个对象Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();invokeMethod(bean, methodName, methodParams);}}/*** 调用任务方法** @param bean 目标对象* @param methodName 方法名称* @param methodParams 方法参数*/private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,InvocationTargetException{if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0){// 携带参数执行方法Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));method.invoke(bean, getMethodParamsValue(methodParams));}else{// 无参执行方法Method method = bean.getClass().getMethod(methodName);method.invoke(bean);}}/*** 校验是否为为class包名* * @param invokeTarget 名称* @return true是 false否*/public static boolean isValidClassName(String invokeTarget){return StringUtils.countMatches(invokeTarget, ".") > 1;}/*** 获取bean名称* * @param invokeTarget 目标字符串* @return bean名称*/public static String getBeanName(String invokeTarget){// task.nameString beanName = StringUtils.substringBefore(invokeTarget, "(");// taskreturn StringUtils.substringBeforeLast(beanName, ".");}/*** 获取bean方法* * @param invokeTarget 目标字符串* @return method方法*/public static String getMethodName(String invokeTarget){// task.nameString methodName = StringUtils.substringBefore(invokeTarget, "(");// namereturn StringUtils.substringAfterLast(methodName, ".");}/*** 获取method方法参数相关列表* * @param invokeTarget 目标字符串* @return method方法相关参数列表*/public static List<Object[]> getMethodParams(String invokeTarget){// trueString methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");// 判断是否为空if (StringUtils.isEmpty(methodStr)){return null;}String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");// 对参数进行过滤处理List<Object[]> classs = new LinkedList<>();for (int i = 0; i < methodParams.length; i++){String str = StringUtils.trimToEmpty(methodParams[i]);// String字符串类型,以'或"开头if (StringUtils.startsWithAny(str, "'", "\"")){classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class });}// boolean布尔类型,等于true或者falseelse if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)){classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });}// long长整形,以L结尾else if (StringUtils.endsWith(str, "L")){classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class });}// double浮点类型,以D结尾else if (StringUtils.endsWith(str, "D")){classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class });}// 其他类型归类为整形else{classs.add(new Object[] { Integer.valueOf(str), Integer.class });}}return classs;}/*** 获取参数类型* * @param methodParams 参数相关列表* @return 参数类型列表*/public static Class<?>[] getMethodParamsType(List<Object[]> methodParams){Class<?>[] classs = new Class<?>[methodParams.size()];int index = 0;for (Object[] os : methodParams){classs[index] = (Class<?>) os[1];index++;}return classs;}/*** 获取参数值* * @param methodParams 参数相关列表* @return 参数值列表*/public static Object[] getMethodParamsValue(List<Object[]> methodParams){Object[] classs = new Object[methodParams.size()];int index = 0;for (Object[] os : methodParams){classs[index] = (Object) os[0];index++;}return classs;}
}

五、CronUtils类

该类主要用于校验cron表达式是否合法,计算下一次任务执行的时间。位于package com.ruoyi.quartz.util;包下

/*** cron表达式工具类* * @author ruoyi**/
public class CronUtils
{/*** 返回一个布尔值代表一个给定的Cron表达式的有效性** @param cronExpression Cron表达式* @return boolean 表达式是否有效*/public static boolean isValid(String cronExpression){return CronExpression.isValidExpression(cronExpression);}/*** 返回一个字符串值,表示该消息无效Cron表达式给出有效性** @param cronExpression Cron表达式* @return String 无效时返回表达式错误描述,如果有效返回null*/public static String getInvalidMessage(String cronExpression){try{new CronExpression(cronExpression);return null;}catch (ParseException pe){return pe.getMessage();}}/*** 返回下一个执行时间根据给定的Cron表达式** @param cronExpression Cron表达式* @return Date 下次Cron表达式执行时间*/public static Date getNextExecution(String cronExpression){try{CronExpression cron = new CronExpression(cronExpression);return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));}catch (ParseException e){throw new IllegalArgumentException(e.getMessage());}}
}

六、ScheduleUtils类

该类真真用于crud任务的工具类。位于package com.ruoyi.quartz.util;包下

/*** 定时任务工具类* * @author ruoyi**/
public class ScheduleUtils
{/*** 得到quartz任务类** @param sysJob 执行计划* @return 具体执行任务类*/private static Class<? extends Job> getQuartzJobClass(SysJob sysJob){// 是否允许并发(0允许,1禁止)boolean isConcurrent = "0".equals(sysJob.getConcurrent());return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;}/*** 构建任务触发对象*/public static TriggerKey getTriggerKey(Long jobId, String jobGroup){return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);}/*** 构建任务键对象*/public static JobKey getJobKey(Long jobId, String jobGroup){return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);}/*** 创建定时任务*/public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException{// 获取任务类(并行/串行)Class<? extends Job> jobClass = getQuartzJobClass(job);// 构建job信息Long jobId = job.getJobId();String jobGroup = job.getJobGroup();JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();// 表达式调度构建器CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);// 按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)).withSchedule(cronScheduleBuilder).build();// 放入参数,运行时的方法可以获取jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);// 判断是否存在if (scheduler.checkExists(getJobKey(jobId, jobGroup))){// 防止创建时存在数据问题 先移除,然后在执行创建操作scheduler.deleteJob(getJobKey(jobId, jobGroup));}// 判断任务是否过期if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression()))){// 执行调度任务scheduler.scheduleJob(jobDetail, trigger);}// 暂停任务if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())){scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));}}/*** 设置定时任务策略*/public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)throws TaskException{switch (job.getMisfirePolicy()){case ScheduleConstants.MISFIRE_DEFAULT:return cb;case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:return cb.withMisfireHandlingInstructionIgnoreMisfires();case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:return cb.withMisfireHandlingInstructionFireAndProceed();case ScheduleConstants.MISFIRE_DO_NOTHING:return cb.withMisfireHandlingInstructionDoNothing();default:throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()+ "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);}}/*** 检查包名是否为白名单配置* * @param invokeTarget 目标字符串* @return 结果*/public static boolean whiteList(String invokeTarget){// task.name(true)// task.nameString packageName = StringUtils.substringBefore(invokeTarget, "(");// 计算.的个数int count = StringUtils.countMatches(packageName, ".");if (count > 1){// 判断是否为白名单return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);}// 获取任务bean对象Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);// 获取任务bean对象路径String beanPackageName = obj.getClass().getPackage().getName();// 判断包是否在白名单并且不在错误名单return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)&& !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);}
}

这篇关于RuoYi模块功能分析:第八章定时任务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Python中的getopt模块用法小结

《Python中的getopt模块用法小结》getopt.getopt()函数是Python中用于解析命令行参数的标准库函数,该函数可以从命令行中提取选项和参数,并对它们进行处理,本文详细介绍了Pyt... 目录getopt模块介绍getopt.getopt函数的介绍getopt模块的常用用法getopt模

Spring Boot 集成 Quartz并使用Cron 表达式实现定时任务

《SpringBoot集成Quartz并使用Cron表达式实现定时任务》本篇文章介绍了如何在SpringBoot中集成Quartz进行定时任务调度,并通过Cron表达式控制任务... 目录前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启动 Sprin

Linux之计划任务和调度命令at/cron详解

《Linux之计划任务和调度命令at/cron详解》:本文主要介绍Linux之计划任务和调度命令at/cron的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux计划任务和调度命令at/cron一、计划任务二、命令{at}介绍三、命令语法及功能 :at

python logging模块详解及其日志定时清理方式

《pythonlogging模块详解及其日志定时清理方式》:本文主要介绍pythonlogging模块详解及其日志定时清理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录python logging模块及日志定时清理1.创建logger对象2.logging.basicCo

SpringQuartz定时任务核心组件JobDetail与Trigger配置

《SpringQuartz定时任务核心组件JobDetail与Trigger配置》Spring框架与Quartz调度器的集成提供了强大而灵活的定时任务解决方案,本文主要介绍了SpringQuartz定... 目录引言一、Spring Quartz基础架构1.1 核心组件概述1.2 Spring集成优势二、J

Qt spdlog日志模块的使用详解

《Qtspdlog日志模块的使用详解》在Qt应用程序开发中,良好的日志系统至关重要,本文将介绍如何使用spdlog1.5.0创建满足以下要求的日志系统,感兴趣的朋友一起看看吧... 目录版本摘要例子logmanager.cpp文件main.cpp文件版本spdlog版本:1.5.0采用1.5.0版本主要

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu