package com.ruoyi.quartz.util;
|
|
import org.quartz.CronScheduleBuilder;
|
import org.quartz.CronTrigger;
|
import org.quartz.Job;
|
import org.quartz.JobBuilder;
|
import org.quartz.JobDetail;
|
import org.quartz.JobKey;
|
import org.quartz.Scheduler;
|
import org.quartz.SchedulerException;
|
import org.quartz.TriggerBuilder;
|
import org.quartz.TriggerKey;
|
import com.ruoyi.common.constant.ScheduleConstants;
|
import com.ruoyi.common.exception.job.TaskException;
|
import com.ruoyi.common.exception.job.TaskException.Code;
|
import com.ruoyi.quartz.domain.SysJob;
|
|
/**
|
* 定时任务工具类
|
*
|
* @author ruoyi
|
*/
|
public class ScheduleUtils {
|
|
/**
|
* Quartz API的关键接口是:
|
* Scheduler - 与调度程序交互的主要API
|
* Job - 由希望由调度程序执行的组件实现的接口
|
* JobDetail - 用于定义作业的实例
|
* Trigger(即触发器) - 定义执行给定作业的计划的组件
|
* JobBuilder - 用于定义/构建JobDetail实例,用于定义作业的实例
|
* TriggerBuilder - 用于定义/构建触发器实例
|
*/
|
|
|
/**
|
* 得到quartz任务类
|
*
|
* @param sysJob 执行计划
|
* @return 具体执行任务类
|
*/
|
private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {
|
// 查看任务是否允许并发执行
|
boolean isConcurrent = "0".equals(sysJob.getConcurrent());
|
// 根据是否允许并发分别得到对应的class
|
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 {
|
//得到quartz任务类的Class
|
//quartz任务类继承了AbstractQuartzJob类,而该类实现了Job接口
|
Class<? extends Job> jobClass = getQuartzJobClass(job);
|
// 构建job信息
|
//获取任务id
|
Long jobId = job.getJobId();
|
//创建Job对象,获取任务组名
|
String jobGroup = job.getJobGroup();
|
//使用JobBuolder根据quartz任务类的class使用静态方法newJob去build一个JobDetail的实例
|
// 这个实例就可以去执行quartz任务类的相关方法(定义一个Job作业)
|
// withIdentity设置后,就可以在使用时使用其name和group作为Trigger去触发
|
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
|
|
// 表达式调度构建器,作为任务调度的容器
|
// 使用cron表达式
|
// 也使用了建造者模式
|
// 将sys_job表中任务所携带的cron表达式字段赋给Builder
|
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
|
//设置定时任务策略(cron计划策略)
|
cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
|
|
// 按新的cronExpression表达式构建一个新的trigger触发器
|
// 使用withIdentity与上方的Job进行绑定
|
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
|
.withSchedule(cronScheduleBuilder).build();
|
|
// 放入参数,运行时的方法可以获取
|
jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
|
|
// 判断当前scheduler容器中是否存在该任务
|
if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
|
// 防止创建时存在数据问题 先移除,然后在执行创建操作
|
scheduler.deleteJob(getJobKey(jobId, jobGroup));
|
}
|
//使用触发器执行定时任务
|
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 {
|
//判断任务的执行策略(cron计划策略)
|
// 具体请查看ScheduleConstants
|
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);
|
}
|
}
|
}
|