SpringBoot整合Quartz定时任务框架

说到定时任务,估计都用过。

①、比如每天15点给lilei发邮件通知等,这种可以直接使用注解@Scheduled标注在一个方法上

②、但是如果我想每天14点发邮件,那是不是得改代码再重启服务,于是我们想到表达式写到配置文件中,再重启服务,相对于前面的可能简单一点

③、那我们还有没更简单的,达到动态修改执行时间且不需要重启服务,答案是有的。也就是本文所要说的。

本文只是简单写了个demo,具体业务自行修改添加

首先pom.xml引入Quartz

SpringBoot整合Quartz定时任务框架_第1张图片

 
        
            org.quartz-scheduler
            quartz
            
                
                    com.mchange
                    c3p0
                
            
        

创建数据库:

CREATE TABLE `sys_job` (
  `id` varchar(64) NOT NULL COMMENT '任务ID',
  `job_name` varchar(64) NOT NULL DEFAULT '' COMMENT '任务名称',
  `job_group` varchar(64) NOT NULL DEFAULT 'DEFAULT' COMMENT '任务组名',
  `invoke_target` varchar(500) DEFAULT NULL COMMENT '调用目标字符串',
  `cron_expression` varchar(255) DEFAULT '' COMMENT 'cron执行表达式',
  `misfire_policy` varchar(20) DEFAULT '1' COMMENT '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
  `concurrent` char(1) DEFAULT '0' COMMENT '是否并发执行(0允许 1禁止)',
  `status` char(1) DEFAULT '1' 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 '备注信息',
  `full_fixed` int(2) DEFAULT NULL COMMENT '全局设置',
  `cron_description` varchar(255) DEFAULT NULL COMMENT 'cron表达式描述',
  `parameter` varchar(255) DEFAULT NULL COMMENT '参数,功能项',
  PRIMARY KEY (`id`,`job_name`,`job_group`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='定时任务调度表';

对应实体类:

@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@ApiModel(value="SysJob对象", description="定时任务调度表")
public class SysJob extends BaseEntity {

    private static final long serialVersionUID=1L;

    @ApiModelProperty(value = "任务名称")
    private String jobName;

    @ApiModelProperty(value = "任务组名")
    private String jobGroup;

    @ApiModelProperty(value = "调用目标字符串")
    private String invokeTarget;

    @ApiModelProperty(value = "cron执行表达式")
    private String cronExpression;

    @ApiModelProperty(value = "定时描述")
    private String cronDescription;

    @ApiModelProperty(value = "计划执行错误策略(1立即执行 2执行一次 3放弃执行)")
    private String misfirePolicy;

    @ApiModelProperty(value = "是否并发执行(0允许 1禁止)")
    private String concurrent;

    @ApiModelProperty(value = "状态(0正常 1暂停)")
    private String status;

    @ApiModelProperty(value = "创建者")
    private String createBy;

    @ApiModelProperty(value = "创建时间")
    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @ApiModelProperty(value = "更新者")
    private String updateBy;

    @ApiModelProperty(value = "更新时间")
    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

    @ApiModelProperty(value = "备注信息")
    private String remark;


    @ApiModelProperty(value = "参数功能项,即对应的指令 比如:'00000000'")
    private String parameter;


    //@ApiModelProperty(value = "下次执行时间")
    //private LocalDateTime nextExecutionTime;

    @ApiModelProperty(value = "全局定时 0-否| 1-是")
    private Integer fullFixed;
}

任务工具类

public class ScheduleUtil {


    /**
     * 获取任务执行类
     *
     * @param sysJob
     * @return
     * @throws Exception
     */
    private static Class getQuartzJobClass(SysJob sysJob) throws Exception {
        String className = sysJob.getInvokeTarget();
//        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
//        return isConcurrent ? SampleJob.class : QuartzDisallowConcurrentExecution.class;
        Class jobClass = null;
        try {
            if (!isValidClassName(className)) {
                jobClass = (Class) SpringUtils.getBean(className);
            } else {
                jobClass = (Class) Class.forName(className);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new Exception("任务类不存在");
        }


        return jobClass;
    }

    /**
     * 构建任务触发对象
     */
    public static TriggerKey getTriggerKey(String jobId, String jobGroup) {
        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
    }

    /**
     * 构建任务键对象
     */
    public static JobKey getJobKey(String jobId, String jobGroup) {
        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
    }

    /**
     * 创建定时任务
     */
    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws Exception {
        Class jobClass = getQuartzJobClass(job);
        // 构建job信息
        String jobId = job.getId();
        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表达式构建一个新的trigger
        CronTrigger 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));
        }

        scheduler.scheduleJob(jobDetail, trigger);

//        // 暂停任务
//        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
//            scheduler.pauseJob(getJobKey(jobId, jobGroup));
//        }
    }

    /**
     * 设置定时任务策略
     */
    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) throws Exception {
        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 RuntimeException("The task misfire policy '" + job.getMisfirePolicy()
                        + "' cannot be used in cron schedule tasks");
        }
    }

    public static boolean isValidClassName(String invokeTarget) {
        return StringUtils.countMatches(invokeTarget, ".") > 1;
    }

}
}
@Service
public class SysJobServiceImpl extends ServiceImpl implements ISysJobService {

    @Autowired
    private Scheduler scheduler;


    /**
     * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
     */
    @PostConstruct
    public void init() throws Exception {
        scheduler.clear();
        List jobList = baseMapper.selectList(new QueryWrapper<>());
        for (SysJob job : jobList) {
            ScheduleUtil.createScheduleJob(scheduler, job);
        }
    }

    /**
     * 保存
     *
     * @param sysJob
     * @return
     * @throws Exception
     */
    @Override
    public boolean insert(SysJob sysJob) throws Exception {
        boolean save = save(sysJob);
        if (save) {
            ScheduleUtil.createScheduleJob(scheduler, sysJob);
        }
        return save;
    }

    @Override
    public boolean deleteJob(SysJob job) throws Exception {
        String jobId = job.getId();
        String jobGroup = job.getJobGroup();
        boolean del = removeById(jobId);
        if (del) {
            scheduler.deleteJob(ScheduleUtil.getJobKey(jobId, jobGroup));
        }
        return del;
    }

    @Override
    public boolean deleteJob(String primary) throws Exception {
        SysJob sysJob = this.getBaseMapper().selectOne(new QueryWrapper<>());
        return deleteJob(sysJob);
    }

    @Override
    public void deleteByPrimarys(String[] jobIds) throws Exception {
        for (String jobId : jobIds) {
            SysJob job = baseMapper.selectById(jobId);
            deleteJob(job);
        }
    }

    @Override
    public boolean updateByPrimary(SysJob sysJob) throws Exception {

        SysJob properties = baseMapper.selectById(sysJob.getId());
        boolean update = update(sysJob, new QueryWrapper<>());
        if (update) {
            updateSchedulerJob(sysJob, properties.getJobGroup());
        }
        return update;
    }

    /**
     * @param page
     * @param queryWrapper
     * @描述:分页
     */
    @Override
    public IPage page(IPage page, QueryWrapper queryWrapper) throws Exception {
        return baseMapper.selectPage(page, queryWrapper);
    }

    /**
     * @param queryWrapper
     * @描述:条件查询
     */
    @Override
    public List select(Wrapper queryWrapper) throws Exception {
        return baseMapper.selectList(queryWrapper);
    }




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

}
@Component("sampleJob")
public class SampleJob extends AbstractQuartzJob {


    //Job的实例是在真正调度JobDetail中的Job实现类时进行实例化的,此对象由框架本身进行管理,所以实例化的对象并没有交给Spring来管理


    // 需要注入的依赖bean
    private static ITaskService taskService;


    // 定义一个set方法
    @Autowired
    public void setTaskService(ITaskService taskService) {
        SampleJob.taskService = taskService;
    }


//    private ITaskService taskService = SpringUtils.getBean( "taskService");

    @Override
    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {
        System.out.println("start");
        System.out.println("sysJob = " + sysJob);
        System.out.println("end");
//        String taskCode = context.getJobDetail().getKey().getName();
//        //具体任务执行的业务
//        taskService.command(sysJob);
    }
}

最终看下测试效果

SpringBoot整合Quartz定时任务框架_第2张图片

 完美!

你可能感兴趣的:(spring,boot)