Quartz框架(九)— 动态操作Quartz定时任务

Quartz框架(一)—Quartz的基本配置
Quartz框架(二)—jobstore数据库表字段详解
Quartz框架(三)—任务的并行/串行执行
Quartz框架(四)—misfire处理机制
Quartz框架(五)— 有状态的job和无状态job
Quartz框架(六)— Trigger状态转换
Quartz框架(七)— Quartz集群原理
Quartz框架(八)— Quartz实现异步通知
Quartz框架(九)— 动态操作Quartz定时任务
Quartz框架(十)监听

1. 如何创建一个任务

方法一:JobDetailFactoryBean或者CronTriggerFactoryBean

如何创建一个复杂的Bean对象,我们可以借助FactoryBean。而巧妙的是,JobDetailFactoryBean或者CronTriggerFactoryBean都实现了FactoryBean接口和InitializingBean接口。虽然我们new JobDetailFactoryBean(),但是实际上是将JobDetail交由的IOC管理。而InitializingBean接口会在属性装载完毕之后,自动的回调afterPropertiesSet()方法,完成Bean对象的最终构建:

    @Bean
    public JobDetailFactoryBean jobDetail(){
        //查询数据库或者配置文件
        JobDetailFactoryBean jobDetailFactoryBean=new JobDetailFactoryBean();
        jobDetailFactoryBean.setName("");
        jobDetailFactoryBean.setBeanName("");
        jobDetailFactoryBean.setJobClass((Class) aClass);
        jobDetailFactoryBean.setGroup("");
        jobDetailFactoryBean.setDurability(true);
        return jobDetailFactoryBean;
    }

而实际上更加直观的写法:

     JobDetailFactoryBean jobFactory = new JobDetailFactoryBean();
     jobFactory.setName("");
     jobFactory.setBeanName("");
     jobFactory.setJobClass((Class) aClass);
     jobFactory.setGroup("");
     jobFactory.setDurability(true);
     jobFactory.afterPropertiesSet();
     //完成JobDetail的创建
     JobDetail jobDetail= jobFactory.getObject();

方法二:使用建筑者模式创建Job或者Trigger

这种方式是通过建筑者模式创建Job或者Trigger。也是更加的优雅。

    //创建Job
    public static JobDetail getJobDetail(JobKey jobKey, String description, boolean jobShouldRecover, JobDataMap jobDataMap, Class jobClass) {

        return JobBuilder.newJob(jobClass)
                .withIdentity(jobKey)
                .withDescription(description)
                .setJobData(jobDataMap)
                .usingJobData(jobDataMap)   //设置JobDataMap字段
                .requestRecovery(jobShouldRecover)
                .storeDurably()  //表示当没有触发器与之关联时,仍然将job继续保存在Scheduler中
                .build();
    }
    //创建Trigger
    public static Trigger getCornTrigger(TriggerKey triggerKey, String description, JobDataMap jobDataMap, String cronExpression, JobKey jobKey) {
        return TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withDescription(description)
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                .forJob(jobKey.getName(), jobKey.getGroup()) //制定Trigger和Job的关联关系
                .usingJobData(jobDataMap)  //具体执行的方法中可以拿到这个传进去的信息。
                .build();
    }

2. 任务的动态操作

首先我们需要在项目启动时Spring容器启动完毕,去加载自定义定时配置表的配置,动态的去创建任务。那么需要实现CommandLineRunner/ApplicationRunner接口。
SpringBoot启动时初始化方法集合

实际上,动态操作定时任务,本质上就是操作scheduler(调度器)中的内容,所以实际上便是直接调用org.quartz.Scheduler类。然后根据自身业务进行扩展,代码就在附录中。

3. 注意事项

JobDataMap在Job和Trigger存储的数据并不一致。

@Slf4j
public class TestJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        log.info("Job中的JobDataMap"+JSONObject.toJSONString(jobDataMap));
        JobDataMap jobDataMap1 = context.getTrigger().getJobDataMap();
        log.info("Trigger中的JobDataMap"+JSONObject.toJSONString(jobDataMap1));
        log.info("【定时任务测试--开始】");
    }
}

若是我们调用org.quartz.Scheduler中的triggerJob方法,立即执行一次定时任务,并且传入了JobDataMap,实际上context.getTrigger().getJobDataMap();才可以获取到。

 void triggerJob(JobKey jobKey, JobDataMap data)
        throws SchedulerException;

附录

动态操作定时的完整代码:

/**
 * Created by EalenXie on 2019/7/10 13:49.
 * 核心其实就是Scheduler的功能 , 这里只是非常简单的示例说明其功能
 * 如需根据自身业务进行扩展 请参考 {@link org.quartz.Scheduler}
 */
@Slf4j
@Service
public class QuartzJobService {

    //Quartz定时任务核心的功能实现类
    private Scheduler scheduler;

    public QuartzJobService(@Autowired SchedulerFactoryBean schedulerFactoryBean) {
        scheduler = schedulerFactoryBean.getScheduler();
    }

    /**
     * 创建和启动 定时任务
     * {@link org.quartz.Scheduler#scheduleJob(JobDetail, Trigger)}
     *
     * @param define 定时任务
     */
    public void scheduleJob(TaskDefine define) throws SchedulerException {
        //1.定时任务 的 名字和组名
        JobKey jobKey = define.getJobKey();
        //2.定时任务 的 元数据
        JobDataMap jobDataMap = getJobDataMap(define.getJobDataMap());
        //3.定时任务 的 描述
        String description = define.getDescription();
        //4.定时任务 的 逻辑实现类
        Class jobClass = define.getJobClass();
        //5.定时任务 的 cron表达式
        String cron = define.getCronExpression();
        JobDetail jobDetail = getJobDetail(jobKey, description, jobDataMap, jobClass);
        Trigger trigger = getTrigger(jobKey, description, jobDataMap, cron);
        scheduler.scheduleJob(jobDetail, trigger);
    }


    /**
     * 暂停Job
     * {@link org.quartz.Scheduler#pauseJob(JobKey)}
     */
    public void pauseJob(JobKey jobKey) throws SchedulerException {
        scheduler.pauseJob(jobKey);
    }

    /**
     * 恢复Job
     * {@link org.quartz.Scheduler#resumeJob(JobKey)}
     */
    public void resumeJob(JobKey jobKey) throws SchedulerException {
        scheduler.resumeJob(jobKey);
    }

    /**
     * 删除Job
     * {@link org.quartz.Scheduler#deleteJob(JobKey)}
     */
    public void deleteJob(JobKey jobKey) throws SchedulerException {
        scheduler.deleteJob(jobKey);
    }


    /**
     * 修改Job 的cron表达式
     */
    public boolean modifyJobCron(TaskDefine define) {
        String cronExpression = define.getCronExpression();
        //1.如果cron表达式的格式不正确,则返回修改失败
        if (!CronExpression.isValidExpression(cronExpression)) return false;
        JobKey jobKey = define.getJobKey();
        TriggerKey triggerKey = new TriggerKey(jobKey.getName(), jobKey.getGroup());
        try {
            CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            JobDataMap jobDataMap = getJobDataMap(define.getJobDataMap());
            //2.如果cron发生变化了,则按新cron触发 进行重新启动定时任务
            if (!cronTrigger.getCronExpression().equalsIgnoreCase(cronExpression)) {
                CronTrigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                        .usingJobData(jobDataMap)
                        .build();
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (SchedulerException e) {
            log.error("printStackTrace", e);
            return false;
        }
        return true;
    }


    /**
     * 获取定时任务的定义
     * JobDetail是任务的定义,Job是任务的执行逻辑
     *
     * @param jobKey      定时任务的名称 组名
     * @param description 定时任务的 描述
     * @param jobDataMap  定时任务的 元数据
     * @param jobClass    {@link org.quartz.Job} 定时任务的 真正执行逻辑定义类
     */
    public JobDetail getJobDetail(JobKey jobKey, String description, JobDataMap jobDataMap, Class jobClass) {
        return JobBuilder.newJob(jobClass)
                .withIdentity(jobKey)
                .withDescription(description)
                .setJobData(jobDataMap)
                .usingJobData(jobDataMap)
                .requestRecovery()
                .storeDurably()
                .build();
    }


    /**
     * 获取Trigger (Job的触发器,执行规则)
     *
     * @param jobKey         定时任务的名称 组名
     * @param description    定时任务的 描述
     * @param jobDataMap     定时任务的 元数据
     * @param cronExpression 定时任务的 执行cron表达式
     */
    public Trigger getTrigger(JobKey jobKey, String description, JobDataMap jobDataMap, String cronExpression) {
        return TriggerBuilder.newTrigger()
                .withIdentity(jobKey.getName(), jobKey.getGroup())
                .withDescription(description)
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                .usingJobData(jobDataMap)
                .build();
    }


    public JobDataMap getJobDataMap(Map map) {
        return map == null ? new JobDataMap() : new JobDataMap(map);
    }


}

文章参考

《SpringBoot整合Quartz作为调度中心使用完整实例》

你可能感兴趣的:(Quartz框架(九)— 动态操作Quartz定时任务)