springboot Quartz 实现动态定时任务

                         springboot Quartz 实现动态定时任务
                           实现上参考ruoyi的quartz

一.引言

Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,EJB作业预构 建,JavaMail及其它,支持cron-like表达式等等。

该项目已经被 Terracotta收购。

二.实战

1.在springboot 中的maven中导入jar

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.3</version>
</dependency>

2.配置quartz

package com.nhiot.web.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
public class QuartzConfiguration
{

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
    {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);

        // quartz参数
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", "nhiotScheduler");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        // 线程池配置
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "20");
        prop.put("org.quartz.threadPool.threadPriority", "5");
        // JobStore配置
        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
        // 集群配置
        prop.put("org.quartz.jobStore.isClustered", "true");
        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");

        // sqlserver 启用
        // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
        prop.put("org.quartz.jobStore.tablePrefix", "qrtz_");
        factory.setQuartzProperties(prop);

        factory.setSchedulerName("nhiotScheduler");
        // 延时启动
        factory.setStartupDelay(1);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        // 可选,QuartzScheduler
        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
        factory.setOverwriteExistingJobs(true);
        // 设置自动启动,默认为true
        factory.setAutoStartup(true);

        return factory;
    }

}

3.创建quartz 需要的表
在这里插入图片描述
4.创建任务类

package com.nhiot.entity.quartz;


import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.nhiot.constants.ScheduleConstants;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

/**
 * @Description
 *
 * @Author www
 * @Date 2020/5/7 17:13
 *
 **/
@Data
@Entity
@Table(name = "t_task")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})
public class SysTask implements Serializable
{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(columnDefinition = "BigInt(10) COMMENT '主键ID'")
     private Long id;

    @Column(columnDefinition = "VARCHAR(255) COMMENT '任务名'")
    private String jobName;

    @Column(columnDefinition = "VARCHAR(255) COMMENT '任务描述'")
    private String description;


    @Column(columnDefinition = "VARCHAR(255) COMMENT 'cron表达式'")
    private String cronExpression;

    @Column(columnDefinition = "VARCHAR(255) COMMENT '任务执行时调用哪个类的方法 包名+类名'")
    private String beanClass;


    @Column(columnDefinition = "VARCHAR(255) COMMENT '计划策略'")
    @ApiModelProperty("计划策略-0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行")
    private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;

    /** 是否并发执行(0允许 1禁止) */
    @Column(columnDefinition = "VARCHAR(255) COMMENT '并发执行'")
    @ApiModelProperty("并发执行-0=允许,1=禁止")
    private String concurrent="0";

    @Column(columnDefinition = "VARCHAR(255) COMMENT '组织ID'")
    @ApiModelProperty("组织Id")
    private String  organizationId;

    @Column(columnDefinition = "VARCHAR(255) COMMENT '任务状态'")
    private String jobStatus="0";

    @Column(columnDefinition = "VARCHAR(255) COMMENT '任务分组'")
    private String jobGroup;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @CreatedDate
    @Column(columnDefinition = "DATETIME COMMENT '创建时间'")
    private Date createTime;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @LastModifiedDate
    @Column(columnDefinition = "DATETIME COMMENT '修改时间'")
    private Date updateTime;

    @CreatedBy
    @Column(columnDefinition = "VARCHAR(255) COMMENT '创建人'")
    private String createBy;

    @Column(columnDefinition = "VARCHAR(255) COMMENT '修改人'")
    @LastModifiedBy
    private String updateBy;


    @Version
    @ApiModelProperty(value = "版本号")
    @Column(columnDefinition = "int(10) COMMENT '版本号'")
    private int versionId;



}

定时任务执行日志类

package com.nhiot.entity.quartz;


import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

/**
 * 定时任务调度日志表 sys_task_log
 * 
 * @author www
 */
@Data
@Entity
@Table(name = "t_task_log")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})
public class SysTaskLog implements Serializable
{
    private static final long serialVersionUID = 1L;

    /** ID */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(columnDefinition = "BigInt(10) COMMENT '主键ID'")
    private Long id;

    /** 任务名称 */
    @Column(columnDefinition = "VARCHAR(255) COMMENT '任务名称'")
    private String jobName;

    /** 任务组名 */
    @Column(columnDefinition = "VARCHAR(255) COMMENT '任务组名'")
    private String jobGroup;

    /** 调用目标字符串 */
    @Column(columnDefinition = "VARCHAR(255) COMMENT '调用目标字符串'")
    private String invokeTarget;

    /** 日志信息 */
    @Column(columnDefinition = "VARCHAR(500) COMMENT '日志信息'")
    private String jobMessage;

    /** 执行状态(0正常 1失败) */
    @Column(columnDefinition = "VARCHAR(20) COMMENT '执行状态(0正常 1失败)'")
    private String status;

    /** 异常信息 */
    @Column(columnDefinition = "VARCHAR(2000) COMMENT '异常信息'")
    private String exceptionInfo;

    /** 开始时间 */
    @Column(columnDefinition = "DATETIME COMMENT '开始时间'")
    private Date startTime;

    /** 结束时间 */
    @Column(columnDefinition = "DATETIME COMMENT '结束时间'")
    private Date endTime;


}

5.写controller控制器

      @Autowired
       private TaskService taskService;


     @RequestMapping(value = "/saveOrUpdate",method =  RequestMethod.POST)
     @ApiOperation("添加/修改定时任务")
     public Result<String> saveOrUpdate(@RequestBody  TaskAddAndEditRequest request)
     {
         return  taskService.saveOrUpdate(request);
     }



      @RequestMapping(value = "/detail",method = RequestMethod.GET)
      @ApiOperation("查询定时任务详情")
     public Result<SysTask> detailTask(String id)
     {
         return taskService.detailTask(id);
     }


     @RequestMapping(value = "/delete/ids",method = RequestMethod.DELETE)
     @ApiOperation("删除定时任务")
     public Result<String> deleteTaskByIds(String ids)
     {
         try {
             return  taskService.deleteTaskByIds(ids);
         } catch (SchedulerException e) {
             e.printStackTrace();
         }
         return null;
     }

    /**
     * 任务调度立即执行一次
     */
    @PostMapping("/run")
    @ResponseBody
    public Result<String> run(String id) throws SchedulerException
    {
        taskService.run(id);
        return Result.<String>builder().success().build();
    }

6.service实现类

 @Autowired
    private TaskRepository taskRepository;


    @Autowired
    @Qualifier("schedulerFactoryBean")
    private Scheduler scheduler;




    /**
     * @Method
     * @Author www
     * @Version  1.0
     * @Description 添加/修改定时任务
     * @Return
     * @Date 2020/8/17 16:58
     */
    @Override
    public Result<String> saveOrUpdate(TaskAddAndEditRequest request)
    {
        SysTask sysTask = null;
        if(request.getId()==null)
        {
            sysTask = new SysTask();
        }else{
            sysTask = taskRepository.getOne(request.getId());
        }
        BeanUtils.copyPropertiesExcludeNull(request, sysTask);
        sysTask.setBeanClass("com.nhiot.service.bengbu.impl.BengbuServiceImpl.uploadAttendance('"+request.getJobGroup()+"')");
        sysTask.setConcurrent("0");
        sysTask.setCronExpression(CronUtils.resetCronExpression(request.getCronExpression()));
        if(!CronUtils.isValid(sysTask.getCronExpression()))
        {
             sysTask.setCronExpression(request.getCronExpression());
        }
        SysTask sysTask1 = taskRepository.saveAndFlush(sysTask);
        try {
            updateSchedulerJob(sysTask1,sysTask1.getJobGroup());
        } catch (SchedulerException e) {
            e.printStackTrace();
        } catch (TaskException e) {
            e.printStackTrace();
        }
        return Result.<String>builder().success().build();
    }



    /**
     * 项目启动时,初始化定时器
     主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
     */
    @PostConstruct
    public void init() throws SchedulerException, TaskException
    {
        scheduler.clear();
        List<SysTask> taskList = taskRepository.findAll();
        for (SysTask sysTask : taskList)
        {
            System.out.println(sysTask.getJobName());
            ScheduleUtils.createScheduleJob(scheduler, sysTask);
        }
    }

    /**
     * @Method
     * @Author www
     * @Version  1.0
     * @Description 查询定时任务详情
     * @Return
     * @Date 2020/8/17 17:23
     */
    @Override
    public Result<SysTask> detailTask(String id)
    {
        SysTask sysTask = taskRepository.findByJobGroup(id);
        return Result.<SysTask>builder().success().data(sysTask).build();
    }

    /**
     * @Method
     * @Author www
     * @Version  1.0
     * @Description 删除定时任务
     * @Return
     * @Date 2020/8/27 10:38
     */
    @Override
    public Result<String> deleteTask(String id) throws SchedulerException
    {
        if(StringUtils.isNotEmpty(id))
        {
            SysTask sysTask = taskRepository.getOne(Long.valueOf(id));
            String jobGroup = sysTask.getJobGroup();
            taskRepository.delete(sysTask);
            scheduler.deleteJob(ScheduleUtils.getJobKey(Long.valueOf(id), jobGroup));
        }
        return Result.<String>builder().success().build();
    }



    /**
     * @Method
     * @Author www
     * @Version  1.0
     * @Description 批量删除定时任务
     * @Return
     * @Date 2020/8/19 9:03
     */
    @Override
    public Result<String> deleteTaskByIds(String ids) throws SchedulerException
    {
        if(StringUtils.isNotEmpty(ids))
        {
            String[] id = ids.split(",");
            for(int i=0;i<id.length;++i)
            {
                deleteTask(id[i]);
            }
        }
        return Result.<String>builder().success().build();
    }

    @Override
    public void run(String id)
    {
        try {
            SysTask sysTask = taskRepository.getOne(Long.valueOf(id));
            // 参数
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(ScheduleConstants.TASK_PROPERTIES, sysTask);
            scheduler.triggerJob(ScheduleUtils.getJobKey(Long.valueOf(id), sysTask.getJobGroup()), dataMap);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }

    /**
     * 更新任务
     *
     * @param sysTask 任务对象
     * @param jobGroup 任务组名
     */
    public void updateSchedulerJob(SysTask sysTask, String jobGroup) throws SchedulerException, TaskException
    {
        Long id = sysTask.getId();
        // 判断是否存在
        JobKey jobKey = ScheduleUtils.getJobKey(id, jobGroup);
        if (scheduler.checkExists(jobKey))
        {
            // 防止创建时存在数据问题 先移除,然后在执行创建操作
            scheduler.deleteJob(jobKey);
        }
        ScheduleUtils.createScheduleJob(scheduler, sysTask);
    }

用到的utils以及实体类

package com.nhiot.service.quartz;

import com.nhiot.constants.ScheduleConstants;
import com.nhiot.entity.quartz.SysTask;
import com.nhiot.entity.quartz.SysTaskLog;
import com.nhiot.exception.ExceptionUtil;
import com.nhiot.repository.quartz.TaskLogRepository;
import com.nhiot.spring.SpringUtils;
import com.nhiot.util.BeanUtils;

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 java.util.Date;

/**
 * 抽象quartz调用
 *
 * @author www
 */
public abstract class AbstractQuartzJob implements Job
{
    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);

    /**
     * 线程本地变量
     */
    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException
    {
        SysTask sysTask = new SysTask();
        BeanUtils.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES),sysTask);
        try
        {
            before(context, sysTask);
            if (sysTask != null)
            {
                doExecute(context, sysTask);
            }
            after(context, sysTask, null);
        }
        catch (Exception e)
        {
            log.error("任务执行异常  - :", e);
            after(context, sysTask, e);
        }
    }

    /**
     * 执行前
     *
     * @param context 工作执行上下文对象
     * @param sysTask 系统计划任务
     */
    protected void before(JobExecutionContext context, SysTask sysTask)
    {
        System.out.println(sysTask.getJobName());
        threadLocal.set(new Date());
    }

    /**
     * 执行后
     *
     * @param context 工作执行上下文对象
     * @param sysTask 系统计划任务
     */
    protected void after(JobExecutionContext context, SysTask sysTask, Exception e)
    {
        Date startTime = threadLocal.get();
        threadLocal.remove();

        final SysTaskLog sysTaskLog = new SysTaskLog();
        sysTaskLog.setJobName(sysTask.getJobName());
        sysTaskLog.setJobGroup(sysTask.getJobGroup());
        sysTaskLog.setInvokeTarget(sysTask.getBeanClass());
        sysTaskLog.setStartTime(startTime);
        sysTaskLog.setEndTime(new Date());
        long runMs = sysTaskLog.getEndTime().getTime() - sysTaskLog.getStartTime().getTime();
        sysTaskLog.setJobMessage(sysTaskLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
        if (e != null)
        {
            sysTaskLog.setStatus("1");
            e.printStackTrace();
            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
            sysTaskLog.setExceptionInfo(errorMsg);
        }
        else
        {
            sysTaskLog.setStatus("0");
        }
        // 写入数据库当中
        SpringUtils.getBean(TaskLogRepository.class).saveAndFlush(sysTaskLog);
    }

    /**
     * 执行方法,由子类重载
     *
     * @param context 工作执行上下文对象
     * @param sysTask 系统计划任务
     * @throws Exception 执行过程中的异常
     */
    protected abstract void doExecute(JobExecutionContext context, SysTask sysTask) throws Exception;
}

CronUtils

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());
        }
    }

    /**
     * 修改定时任务时间
     */
    public static String resetCronExpression(String cronExpression)
    {
        String[] str = cronExpression.split(" ");
        StringBuffer re = new StringBuffer();
        str[1]= String.valueOf(DateUtils.getMinute(new Date()));
        for (int i=0;i<str.length;++i) {
            if(i==0) {
                re.append(str[i]);
            }else {
                re.append(" "+str[i]);
            }
        }
        return re.toString();
    }
}

JobInvokeUtils

public class JobInvokeUtil
{
    /**
     * 执行方法
     *
     * @param sysTask 系统任务
     */
    public static void invokeMethod(SysTask sysTask) throws Exception
    {
        String invokeTarget = sysTask.getBeanClass();
        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 ( methodParams!=null &&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或者false
            else if (StringUtils.equals(str, "true") || StringUtils.equalsIgnoreCase(str, "false"))
            {
                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
            }
            // long长整形,包含L
            else if (StringUtils.containsIgnoreCase(str, "L"))
            {
                classs.add(new Object[] { Long.valueOf(StringUtils.replaceIgnoreCase(str, "L", "")), Long.class });
            }
            // double浮点类型,包含D
            else 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;
    }
}

QuartzDisallowConcurrentExecution:

/**
 * 定时任务处理(禁止并发执行)
 * 
 * @author www
 *
 */
@DisallowConcurrentExecution
public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
{
    @Override
    protected void doExecute(JobExecutionContext context, SysTask sysTask) throws Exception
    {
        JobInvokeUtil.invokeMethod(sysTask);
    }
}

QuartzJobExecution:

/**
 * 定时任务处理(允许并发执行)
 * 
 * @author www
 *
 */
public class QuartzJobExecution extends AbstractQuartzJob
{
    @Override
    protected void doExecute(JobExecutionContext context, SysTask sysTask) throws Exception
    {
        JobInvokeUtil.invokeMethod(sysTask);
    }
}

ScheduleUtils:

/**
 * 定时任务工具类
 * 
 * @author www
 *
 */
public class ScheduleUtils
{
    /**
     * 得到quartz任务类
     *
     * @param sysTask 执行计划
     * @return 具体执行任务类
     */
    private static Class<? extends Job> getQuartzJobClass(SysTask sysTask)
    {
        boolean isConcurrent = "0".equals(sysTask.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, SysTask sysTask) throws SchedulerException, TaskException
    {
        Class<? extends Job> jobClass = getQuartzJobClass(sysTask);
        // 构建job信息
        Long  id = sysTask.getId();
        String jobGroup = sysTask.getJobGroup();
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(id, jobGroup)).build();

        // 表达式调度构建器
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysTask.getCronExpression());
        cronScheduleBuilder = handleCronScheduleMisfirePolicy(sysTask, cronScheduleBuilder);

        // 按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(id, jobGroup))
                .withSchedule(cronScheduleBuilder).build();

        // 放入参数,运行时的方法可以获取
        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, sysTask);

        // 判断是否存在
        if (scheduler.checkExists(getJobKey(id, jobGroup)))
        {
            // 防止创建时存在数据问题 先移除,然后在执行创建操作
            scheduler.deleteJob(getJobKey(id, jobGroup));
        }

        scheduler.scheduleJob(jobDetail, trigger);

        // 暂停任务
        if (sysTask.getJobStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))
        {
            scheduler.pauseJob(ScheduleUtils.getJobKey(id, jobGroup));
        }
    }

    /**
     * 设置定时任务策略
     */
    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysTask sysTask, CronScheduleBuilder cb)
            throws TaskException
    {
        switch (sysTask.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 '" + sysTask.getMisfirePolicy()
                        + "' cannot be used in cron schedule tasks", TaskException.Code.CONFIG_ERROR);
        }
    }
}

效果:
在这里插入图片描述

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值