美文网首页Quartz框架
Quartz框架(九)— 动态操作Quartz定时任务

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

作者: 小胖学编程 | 来源:发表于2019-08-09 16:11 被阅读0次

    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<? extends Job>) aClass);
            jobDetailFactoryBean.setGroup("");
            jobDetailFactoryBean.setDurability(true);
            return jobDetailFactoryBean;
        }
    

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

         JobDetailFactoryBean jobFactory = new JobDetailFactoryBean();
         jobFactory.setName("");
         jobFactory.setBeanName("");
         jobFactory.setJobClass((Class<? extends Job>) 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<? extends Job> 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<? extends Job> 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<? extends Job> 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定时任务

        本文链接:https://www.haomeiwen.com/subject/jmcfjctx.html