Springboot--整合Mybatis与定时任务quartz

news/2024/4/17 16:07:08

文章目录

  • 前言
  • 一、Mybatis 集成
    • 1.1 Springboot 整合mybatis:
    • 1.2 任务表:
    • 1.3 job 有关代码:
      • 1.3.1 entity:
      • 1.3.2 mapper:
      • 1.3.3 service:
      • 1.3.4 测试代码:
  • 二、quartz 集成:
    • 2.1 项目启动后获取任务:
    • 2.2 将任务交由quartz 管理:
      • 2.2.1 ScheduleUtils 封装任务:
      • 2.2.2 任务执行业务类:
      • 2.2.3 记录任务的执行:
  • 总结


前言

在 Springboot–整合定时任务quartz–集群篇 中已经介绍了如何集群并使用quartz ,但是我们并不想每个定时任务都去重复的创建JobDetail 和 Trigger,那么是否可以将任务存储在mysql 中,然后在项目启动完成后,统一的去加载任务呢,答案是肯定可以的;


一、Mybatis 集成

因为要将任务放入到mysql 中所以首先需要集成Mybatis;本文环境,业务系统和 quartz 是两个数据源;

1.1 Springboot 整合mybatis:

可以参考: cloud项目搭建系列–4整合mybatis-plus 整合业务系统的数据源
可以参考:Springboot整合定时任务quartz(非集群) 中 2.3 Springboot 整合quartz 持久化(独立数据源) 整合quartz 数据源;

1.2 任务表:

CREATE TABLE `sys_job` (`job_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '任务ID',`job_name` varchar(64) NOT NULL DEFAULT '' COMMENT '任务名称',`job_group` varchar(64) NOT NULL DEFAULT 'DEFAULT' COMMENT '任务组名',`invoke_target` varchar(500) NOT NULL COMMENT '调用目标字符串',`cron_expression` varchar(255) DEFAULT '' COMMENT 'cron执行表达式',`misfire_policy` varchar(20) DEFAULT '3' COMMENT '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',`concurrent` char(1) DEFAULT '1' COMMENT '是否并发执行(0允许 1禁止)',`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1暂停)',`create_by` varchar(64) DEFAULT '' COMMENT '创建者',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`update_by` varchar(64) DEFAULT '' COMMENT '更新者',`update_time` datetime DEFAULT NULL COMMENT '更新时间',`remark` varchar(500) DEFAULT '' COMMENT '备注信息',PRIMARY KEY (`job_id`,`job_name`,`job_group`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='定时任务调度表';CREATE TABLE `sys_job_log` (`job_log_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '任务日志ID',`job_name` varchar(64) NOT NULL COMMENT '任务名称',`job_group` varchar(64) NOT NULL COMMENT '任务组名',`invoke_target` varchar(500) NOT NULL COMMENT '调用目标字符串',`job_message` varchar(500) DEFAULT NULL COMMENT '日志信息',`status` char(1) DEFAULT '0' COMMENT '执行状态(0正常 1失败)',`exception_info` varchar(2000) DEFAULT '' COMMENT '异常信息',`create_by` varchar(60) DEFAULT NULL COMMENT '创建人',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`update_by` varchar(60) DEFAULT NULL COMMENT '更新人',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`job_log_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='定时任务调度日志表';

1.3 job 有关代码:

1.3.1 entity:

SysJob

package com.example.springmvctest.job.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;import java.time.LocalDateTime;
import java.io.Serializable;
import java.util.Date;import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;/*** <p>* 定时任务调度表* </p>** @author lgx* @since 2024-02-20*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class SysJob implements Serializable {private static final long serialVersionUID = 1L;/*** 任务ID*/@TableId(value = "job_id", type = IdType.AUTO)private Integer jobId;/*** 任务名称*/private String jobName;/*** 任务组名*/private String jobGroup;/*** 调用目标字符串*/private String invokeTarget;/*** cron执行表达式*/private String cronExpression;/*** 计划执行错误策略(1立即执行 2执行一次 3放弃执行)*/private String misfirePolicy;/*** 是否并发执行(0允许 1禁止)*/private String concurrent;/*** 状态(0正常 1暂停)*/private String status;/*** 创建者*/private String createBy;/*** 创建时间*/private Date createTime;/*** 更新者*/private String updateBy;/*** 更新时间*/private Date updateTime;/*** 备注信息*/private String remark;}

SysJobLog:

package com.example.springmvctest.job.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;import java.time.LocalDateTime;
import java.io.Serializable;
import java.util.Date;import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;/*** <p>* 定时任务调度日志表* </p>** @author lgx* @since 2024-02-20*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class SysJobLog implements Serializable {private static final long serialVersionUID = 1L;/*** 任务日志ID*/@TableId(value = "job_log_id", type = IdType.AUTO)private Integer jobLogId;/*** 任务名称*/private String jobName;/*** 任务组名*/private String jobGroup;/*** 调用目标字符串*/private String invokeTarget;/*** 日志信息*/private String jobMessage;/*** 执行状态(0正常 1失败)*/private String status;/*** 异常信息*/private String exceptionInfo;/*** 创建人*/private String createBy;/*** 创建时间*/private Date createTime;/*** 更新人*/private String updateBy;/*** 更新时间*/private Date updateTime;}

1.3.2 mapper:

SysJobLogMapper:

package com.example.springmvctest.mapper;import com.example.springmvctest.job.entity.SysJobLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;/*** <p>* 定时任务调度日志表 Mapper 接口* </p>** @author lgx* @since 2024-02-20*/
public interface SysJobLogMapper extends BaseMapper<SysJobLog> {}

SysJobMapper:

package com.example.springmvctest.mapper;import com.example.springmvctest.job.entity.SysJob;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;/*** <p>* 定时任务调度表 Mapper 接口* </p>** @author lgx* @since 2024-02-20*/
public interface SysJobMapper extends BaseMapper<SysJob> {}

1.3.3 service:

ISysJobLogService:

package com.example.springmvctest.job.service;import com.example.springmvctest.job.entity.SysJobLog;
import com.baomidou.mybatisplus.extension.service.IService;/*** <p>* 定时任务调度日志表 服务类* </p>** @author lgx* @since 2024-02-20*/
public interface ISysJobLogService extends IService<SysJobLog> {}

ISysJobService:

package com.example.springmvctest.job.service;import com.example.springmvctest.job.entity.SysJob;
import com.baomidou.mybatisplus.extension.service.IService;import org.quartz.SchedulerException;import java.util.List;/*** <p>* 定时任务调度表 服务类* </p>** @author lgx* @since 2024-02-20*/
public interface ISysJobService extends IService<SysJob> {/*** 获取quartz调度器的计划任务** @return 调度任务集合*/List<SysJob> getAllJob();
}

SysJobLogServiceImpl:

package com.example.springmvctest.job.service.impl;import com.example.springmvctest.job.entity.SysJobLog;
import com.example.springmvctest.mapper.SysJobLogMapper;
import com.example.springmvctest.job.service.ISysJobLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;/*** <p>* 定时任务调度日志表 服务实现类* </p>** @author lgx* @since 2024-02-20*/
@Service
public class SysJobLogServiceImpl extends ServiceImpl<SysJobLogMapper, SysJobLog> implements ISysJobLogService {}

SysJobServiceImpl:

package com.example.springmvctest.job.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springmvctest.job.entity.SysJob;
import com.example.springmvctest.job.service.ISysJobService;
import com.example.springmvctest.mapper.SysJobMapper;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*** <p>* 定时任务调度表 服务实现类* </p>** @author lgx* @since 2024-02-20*/
@Service
public class SysJobServiceImpl extends ServiceImpl<SysJobMapper, SysJob> implements ISysJobService {@Autowiredprivate Scheduler scheduler;@Overridepublic List<SysJob> getAllJob() {return this.list();}
}

1.3.4 测试代码:

TestQuartzJob:

package com.example.springmvctest.job.service.impl;import com.example.springmvctest.job.service.ISysJobService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Slf4j
@Component("testQuartzJob")
public class TestQuartzJob {@Autowiredprivate ISysJobService sysJobService;public void test(String param1, String param2) {log.debug("quartz job start");String result = sysJobService.test();log.error("test 执行结果", result);}
}

每隔 3s 执行一次任务:

INSERT INTO `sys_job`( `job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES ( 'test', 'DEFAULT', 'testQuartzJob.test(\'param1\',\'param1\')', '0/3 * * * * ? ', '1', '1', '0', 'admin', '2023-09-18 14:07:10', '', '2023-09-18 14:15:08', '');

二、quartz 集成:

接下来就是从mysql 中读取已经存储的任务,并交由quartz 管理即可;

2.1 项目启动后获取任务:

InitJob:

package com.example.springmvctest.job.config;import com.example.springmvctest.job.entity.SysJob;
import com.example.springmvctest.job.service.ISysJobService;
import com.example.springmvctest.job.utils.ScheduleUtils;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Scheduler;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.util.List;@Slf4j
@Component
public class InitJob implements InitializingBean {@Autowiredprivate ISysJobService jobService;@Autowiredprivate Scheduler scheduler;@Overridepublic void afterPropertiesSet() throws Exception {List<SysJob> jobList = jobService.getAllJob();if (CollectionUtils.isEmpty(jobList)) {log.info("not job need to init");return;}for (SysJob job : jobList) {ScheduleUtils.createScheduleJob(scheduler, job);}}
}

2.2 将任务交由quartz 管理:

2.2.1 ScheduleUtils 封装任务:

package com.example.springmvctest.job.utils;import com.example.springmvctest.job.constant.ScheduleConstants;
import com.example.springmvctest.job.entity.SysJob;
import org.quartz.*;/*** 定时任务工具类** @author ruoyi*/
public class ScheduleUtils {/*** 得到quartz任务类** @param sysJob 执行计划* @return 具体执行任务类*/private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {boolean isConcurrent = "0".equals(sysJob.getConcurrent());return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;}/*** 构建任务触发对象*/public static TriggerKey getTriggerKey(Integer jobId, String jobGroup) {String name = ScheduleConstants.TASK_CLASS_NAME + jobId;return TriggerKey.triggerKey(name, jobGroup);}/*** 构建任务键对象*/public static JobKey getJobKey(Integer jobId, String jobGroup) {String name = ScheduleConstants.TASK_CLASS_NAME + jobId;return JobKey.jobKey(name, jobGroup);}/*** 创建定时任务*/public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException {Class<? extends Job> jobClass = getQuartzJobClass(job);// 构建job信息Integer jobId = job.getJobId();String jobGroup = job.getJobGroup();JobKey jobKey = getJobKey(jobId, jobGroup);JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobKey).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(jobKey)) {// 防止创建时存在数据问题 先移除,然后在执行创建操作scheduler.deleteJob(jobKey);}scheduler.scheduleJob(jobDetail, trigger);// 暂停任务if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {scheduler.pauseJob(jobKey);}}/*** 设置定时任务策略*/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", TaskException.Code.CONFIG_ERROR);}}
}

TaskException:

package com.example.springmvctest.job.utils;/*** 计划策略异常* * @author ruoyi*/
public class TaskException extends Exception
{private static final long serialVersionUID = 1L;private Code code;public TaskException(String msg, Code code){this(msg, code, null);}public TaskException(String msg, Code code, Exception nestedEx){super(msg, nestedEx);this.code = code;}public Code getCode(){return code;}public enum Code{TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE}
}

ScheduleConstants:

package com.example.springmvctest.job.constant;/*** 任务调度通用常量** @author ruoyi*/
public class ScheduleConstants {public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";/*** 执行目标key*/public static final String TASK_PROPERTIES = "TASK_PROPERTIES";/*** 默认*/public static final String MISFIRE_DEFAULT = "0";/*** 立即触发执行*/public static final String MISFIRE_IGNORE_MISFIRES = "1";/*** 触发一次执行*/public static final String MISFIRE_FIRE_AND_PROCEED = "2";/*** 不触发立即执行*/public static final String MISFIRE_DO_NOTHING = "3";public enum Status {/*** 正常*/NORMAL("0"),/*** 暂停*/PAUSE("1");private String value;private Status(String value) {this.value = value;}public String getValue() {return value;}}
}

2.2.2 任务执行业务类:

QuartzJobExecution:

package com.example.springmvctest.job.utils;import com.example.springmvctest.job.entity.SysJob;
import org.quartz.JobExecutionContext;/*** 定时任务处理(允许并发执行)** @author ruoyi*/
public class QuartzJobExecution extends AbstractQuartzJob {@Overrideprotected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {JobInvokeUtil.invokeMethod(sysJob);}
}

JobInvokeUtil:

package com.example.springmvctest.job.utils;import com.example.springmvctest.feign.config.StringUtils;
import com.example.springmvctest.job.entity.SysJob;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;/*** 任务执行工具** @author ruoyi*/
public class JobInvokeUtil {/*** 执行方法** @param sysJob 系统任务*/public static void invokeMethod(SysJob sysJob) throws Exception {String invokeTarget = sysJob.getInvokeTarget();String beanName = getBeanName(invokeTarget);String methodName = getMethodName(invokeTarget);List<Object[]> methodParams = getMethodParams(invokeTarget);if (!isValidClassName(beanName)) {Object bean = SpringUtils.getBean(beanName);invokeMethod(bean, methodName, methodParams);} else {Object bean = Class.forName(beanName).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().getDeclaredMethod(methodName, getMethodParamsType(methodParams));method.invoke(bean, getMethodParamsValue(methodParams));} else {Method method = bean.getClass().getDeclaredMethod(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) {String beanName = StringUtils.substringBefore(invokeTarget, "(");return StringUtils.substringBeforeLast(beanName, ".");}/*** 获取bean方法** @param invokeTarget 目标字符串* @return method方法*/public static String getMethodName(String invokeTarget) {String methodName = StringUtils.substringBefore(invokeTarget, "(");return StringUtils.substringAfterLast(methodName, ".");}/*** 获取method方法参数相关列表** @param invokeTarget 目标字符串* @return method方法相关参数列表*/public static List<Object[]> getMethodParams(String invokeTarget) {String 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.contains(str, "'")) {classs.add(new Object[]{StringUtils.replace(str, "'", ""), String.class});}// boolean布尔类型,等于true或者falseelse if (StringUtils.equals(str, "true") || StringUtils.equalsIgnoreCase(str, "false")) {classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});}// long长整形,包含Lelse if (StringUtils.containsIgnoreCase(str, "L")) {classs.add(new Object[]{Long.valueOf(StringUtils.replaceIgnoreCase(str, "L", "")), Long.class});}// double浮点类型,包含Delse if (StringUtils.containsIgnoreCase(str, "D")) {classs.add(new Object[]{Double.valueOf(StringUtils.replaceIgnoreCase(str, "D", "")), 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;}
}

SpringUtils:

package com.example.springmvctest.job.utils;import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;/*** spring工具类 方便在非spring管理环境中获取bean** @author ruoyi*/
@Component
public final class SpringUtils implements ApplicationContextAware {/*** Spring应用上下文环境*/private static ApplicationContext APPLICATION_CONTEXT;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringUtils.APPLICATION_CONTEXT = applicationContext;}/*** 获取对象** @param name* @return Object 一个以所给名字注册的bean的实例* @throws BeansException*/@SuppressWarnings("unchecked")public static <T> T getBean(String name) throws BeansException {return (T) APPLICATION_CONTEXT.getBean(name);}/*** 获取类型为requiredType的对象** @param clz* @return* @throws BeansException*/public static <T> T getBean(Class<T> clz) throws BeansException {T result = (T) APPLICATION_CONTEXT.getBean(clz);return result;}/*** 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true** @param name* @return boolean*/public static boolean containsBean(String name) {return APPLICATION_CONTEXT.containsBean(name);}/*** 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)** @param name* @return boolean* @throws NoSuchBeanDefinitionException*/public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {return APPLICATION_CONTEXT.isSingleton(name);}/*** @param name* @return Class 注册对象的类型* @throws NoSuchBeanDefinitionException*/public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {return APPLICATION_CONTEXT.getType(name);}/*** 如果给定的bean名字在bean定义中有别名,则返回这些别名** @param name* @return* @throws NoSuchBeanDefinitionException*/public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {return APPLICATION_CONTEXT.getAliases(name);}/*** 获取aop代理对象** @param invoker* @return*/@SuppressWarnings("unchecked")public static <T> T getAopProxy(T invoker) {return (T) AopContext.currentProxy();}
}

QuartzDisallowConcurrentExecution:

package com.example.springmvctest.job.utils;import com.example.springmvctest.job.entity.SysJob;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;/*** 定时任务处理(禁止并发执行)** @author ruoyi*/
@DisallowConcurrentExecution
public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob {@Overrideprotected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {JobInvokeUtil.invokeMethod(sysJob);}
}

2.2.3 记录任务的执行:

AbstractQuartzJob:

package com.example.springmvctest.job.utils;import com.example.springmvctest.job.constant.ScheduleConstants;
import com.example.springmvctest.job.entity.SysJob;
import com.example.springmvctest.job.entity.SysJobLog;
import com.example.springmvctest.job.service.ISysJobLogService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;import java.util.Date;/*** 抽象quartz调用** @author ruoyi*/
public abstract class AbstractQuartzJob implements Job {private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {SysJob sysJob = new SysJob();BeanUtils.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES),sysJob);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) {context.put("startTime", new Date());}/*** 执行后** @param context 工作执行上下文对象* @param sysJob  系统计划任务*/protected void after(JobExecutionContext context, SysJob sysJob, Exception e) {Date startTime = (Date) context.get("startTime");SysJobLog sysJobLog = createJobLog(sysJob, startTime, e);SpringUtils.getBean(ISysJobLogService.class).save(sysJobLog);}private SysJobLog createJobLog(SysJob sysJob, Date startTime, Exception e) {SysJobLog sysJobLog = new SysJobLog();sysJobLog.setJobName(sysJob.getJobName());sysJobLog.setJobGroup(sysJob.getJobGroup());sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());long runMs = System.currentTimeMillis() - startTime.getTime();sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");if (e != null) {sysJobLog.setStatus("1");String errorMsg = StringUtils.substring(ExceptionFormatUtil.buildErrorMessage(e), 0, 2000);sysJobLog.setExceptionInfo(errorMsg);} else {sysJobLog.setStatus("0");}return sysJobLog;}/*** 执行方法,由子类重载** @param context 工作执行上下文对象* @param sysJob  系统计划任务* @throws Exception 执行过程中的异常*/protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
}

总结

通过将任务存储于mysql 中,在项目启动后可以获取所有任务,封装JobDetail和 CronTrigger并交由quartz 管理;


https://www.xjx100.cn/news/3293545.html

相关文章

【前端素材】推荐优质后台管理系统Salreo平台模板(附源码)

一、需求分析 当我们从多个层次来详细分析后台管理系统时&#xff0c;可以将其功能和定义进一步细分&#xff0c;以便更好地理解其在不同方面的作用和实际运作。 1. 结构层次 在结构层次上&#xff0c;后台管理系统可以分为以下几个部分&#xff1a; a. 辅助功能模块&#…

阿里云ECS服务器vCPU是什么意思?

阿里云ECS服务器vCPU和CPU是什么意思&#xff1f;CPU和vCPU有什么区别&#xff1f;一台云服务器ECS实例的CPU选项由CPU物理核心数和每核线程数决定&#xff0c;CPU是中央处理器&#xff0c;一个CPU可以包含若干个物理核&#xff0c;通过超线程HT&#xff08;Hyper-Threading&am…

【C++】STL容器之string(修改操作)

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

密码学——离散对数

引言 离散对数 Discrete logarithm 是一种基于同余和原根的对数运算。如 l o g b a logb^a logb

java编程基础实验报告小结,java算法基础面试题

分享第一份Java基础-中级-高级面试集合 Java基础&#xff08;对象线程字符接口变量异常方法&#xff09; Java中级开发&#xff08;底层Spring相关Redis分布式设计模式MySQL高并发锁线程&#xff09; Java高级“程序猿”&#xff08;高并发Redis缓存分布式消息队列高可用微服务…

flutter 封装webview和使用本地网页

最先看到flutter_webview_plugin 用法特别简单 flutter_webview_plugin | Flutter PackagePlugin that allow Flutter to communicate with a native Webview.https://pub-web.flutter-io.cn/packages/flutter_webview_plugin缺点&#xff1a; 没有实现js sdk的功能 没有办法 …

Android 接入指纹识别

接入指纹框架&#xff1a;https://github.com/Tencent/soter implementation com.github.Tencent.soter:soter-wrapper:2.0.91.Application中初始化 class IApplication : Application() {override fun onCreate() {super.onCreate()instance thisinitSort()}private fun in…

瑞_Redis_Redis命令

文章目录 1 Redis命令Redis数据结构Redis 的 key 的层级结构1.0 Redis通用命令1.0.1 KEYS1.0.2 DEL1.0.3 EXISTS1.0.4 EXPIRE1.0.5 TTL 1.1 String类型1.1.0 String类型的常见命令1.1.1 SET 和 GET1.1.2 MSET 和 MGET1.1.3 INCR和INCRBY和DECY1.1.4 SETNX1.1.5 SETEX 1.2 Hash类…