Quartz中的常用组件之间的关系

注意:

本文应用了Quartz入门中的入门案例作为基础


### 1.Job和JobDetail的关系介绍
  • Job:工作任务调度接口,任务类需要实现的接口。该接口中定义了execute方法,类似JDK提供的TimeTask类的run方法。在这里面编写任务执行的业务逻辑
  • Job实例在Quartz中的生命周期:每次调度器执行Job时,它在调用execute方法前会创建一个新的Job实例,当调度完成后,管理的Job对象实例将会被释放,释放的实例会被垃圾回收机制回收
@Slf4j
public class HelloJob implements Job {

    public HelloJob(){
        log.info("实例被创建了");
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) + " | 任务被执行了");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oXQl5leO-1626662449852)(\images\image-20210713112341699.png)]

  • JobDetail:JobDetail为Job实例提供了许多设置属性,已经JobDetaMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助于JobDetail对象来添加Job实例【JobDetail中重要的属性:name[任务实例的唯一标识名称]、group[任务调度实例的组名]、jobClass[任务类信息]、jobDataMap】
@Slf4j
public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        //从调度工厂中获取调度器实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //通过JobBuilder构建一个任务实例
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                //设置任务的唯一实例名称和任务组名称组名
                .withIdentity("job1", "group1")
                //构建实例
                .build();
        //jobDataMap
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        //任务实例的唯一标识名称
        String name = jobDetail.getKey().getName();
        //任务调度实例的组名
        String group = jobDetail.getKey().getGroup();
        //任务类信息
        String clazzName = jobDetail.getKey().getClass().getName();
        log.info("jobDataMap:{}", jobDataMap);
        log.info("任务实例的唯一标识名称:"+name);
        log.info("任务调度实例的组名:"+group);
        log.info("任务类信息:"+clazzName);
        //通过TriggerBuilder构建触发器实例
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                //设置触发器唯一实例名称和触发器的组名
                .withIdentity("trigger1", "group1")
                //执行计划,每五秒执行一次
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
                //立即执行
                .startNow()
                //构建实例
                .build();
        //调度器绑定任务实例和触发器
        scheduler.scheduleJob(jobDetail,trigger);
        //开启定时任务
        scheduler.start();
    }
}

在这里插入图片描述

2.JobExecutionContext的介绍

  • 当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法

  • Job能通过JobExecuteContext对象访问到Quartz运行时的环境以及Job本身的明细数据

    • 获取JobDetail相关信息、获取Trigger相关信息、获取Job类本身的信息
    /**
     * @Author ScholarTang
     * @Date 2021/7/13 10:45
     * @Desc 任务类
     */
    @Slf4j
    public class HelloJob implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            //通过JobExecutionContext获取JobDetail
            JobDetail jobDetail = jobExecutionContext.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            String jobDetailName = jobKey.getName();
            String jobDetailGroup = jobKey.getGroup();
            String jobClazzNameJobDetail = jobKey.getClass().getName();
            log.info("任务实例的唯一标识名称:" + jobDetailName);
            log.info("任务实例的组名:" + jobDetailGroup);
            log.info("任务实例绑定的任务类信息:" + jobClazzNameJobDetail);
            log.info("-----------------------------------------");
            //通过JobExecutionContext获取Trigger
            Trigger trigger = jobExecutionContext.getTrigger();
            TriggerKey triggerKey = trigger.getKey();
            String triggerKeyName = triggerKey.getName();
            String triggerKeyGroup = triggerKey.getGroup();
            String triggerClazzName = triggerKey.getClass().getName();
            log.info("触发器的唯一标识名称:" + triggerKeyName);
            log.info("触发器的组名:" + triggerKeyGroup);
            log.info("触发器绑定的任务类信息:" + triggerClazzName);
            log.info("-----------------------------------------");
            //通过JobExecutionContext
            String jobClazzName = jobExecutionContext.getClass().getName();
            log.info("job类相关的信息:"+jobClazzName);
            log.info("-----------------------------------------");
            log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) + " | 任务被执行了");
        }
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jbXvuZbk-1626662449860)(\images\image-20210713141416712.png)]

3.JobDataMap介绍

3.1.使用Map获取
  • 在进行任务调度时,JobDataMap存储在JobExecutionContent中,非常方便获取
  • JobDataMap可以用来存储任何可序列化的数据对象,当Job实例对象被执行时这些参数都会传递给它
  • JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法来存储基本数据类型
/**
 * @Author ScholarTang
 * @Date 2021/7/13 10:53
 * @Desc 调度器
 */
@Slf4j
public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        //从调度工厂中获取调度器实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //通过JobBuilder构建一个任务实例
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                //设置任务的唯一实例名称和任务组名称组名
                .withIdentity("job1", "group1")
                //设置jobDataMap数据  <<===============
                .usingJobData("message","勇敢牛牛、不怕困难")
                //构建实例
                .build();
        //通过TriggerBuilder构建触发器实例
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                //设置触发器唯一实例名称和触发器的组名
                .withIdentity("trigger1", "group1")
                //设置jobDataMap数据   <<===============
                .usingJobData("username","张三")
                //执行计划,每五秒执行一次
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
                //立即执行
                .startNow()
                //构建实例
                .build();
        //调度器绑定任务实例和触发器
        scheduler.scheduleJob(jobDetail,trigger);
        //开启定时任务
        scheduler.start();
    }
}
/**
 * @Author ScholarTang
 * @Date 2021/7/13 10:45
 * @Desc 任务类
 */
@Slf4j
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //通过JobExecutionContext获取JobDetail
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobKey jobKey = jobDetail.getKey();
        String jobDetailName = jobKey.getName();
        String jobDetailGroup = jobKey.getGroup();
        String jobClazzNameJobDetail = jobKey.getClass().getName();
        log.info("任务实例的唯一标识名称:" + jobDetailName);
        log.info("任务实例的组名:" + jobDetailGroup);
        log.info("任务实例绑定的任务类信息:" + jobClazzNameJobDetail);
        log.info("-----------------------------------------");
        //通过JobExecutionContext获取Trigger
        Trigger trigger = jobExecutionContext.getTrigger();
        TriggerKey triggerKey = trigger.getKey();
        String triggerKeyName = triggerKey.getName();
        String triggerKeyGroup = triggerKey.getGroup();
        String triggerClazzName = triggerKey.getClass().getName();
        log.info("触发器的唯一标识名称:" + triggerKeyName);
        log.info("触发器的组名:" + triggerKeyGroup);
        log.info("触发器绑定的任务类信息:" + triggerClazzName);
        log.info("-----------------------------------------");
        //通过JobExecutionContext
        String jobClazzName = jobExecutionContext.getClass().getName();
        log.info("job类相关的信息:"+jobClazzName);
        log.info("-----------------------------------------");
        //获取JobDetail中JobDataMap中的message内容  <<===============
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String message = jobDataMap.getString("message");
        log.info("从JobDetail-JobDataMap中或到的message内容为:" + message);
        //获取Trigger中JobDataMap中的username内容   <<===============
        JobDataMap triggerJobDataMap = trigger.getJobDataMap();
        String username = triggerJobDataMap.getString("username");
        log.info("从Trigger-JobDataMap中获取到的username内容为:" + username);
        log.info("-----------------------------------------");
        log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) + " | 任务被执行了");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cl461fxc-1626662449862)(\images\image-20210713142744867.png)]

3.2.Job实现类中添加setter方法对应JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化Job实例对象时会自动的调用这些setter方法

调度器的内容是不变的。
注意:如果任务实例和触发器的JobDataMap中使用的是同一个key那么触发器的JobDataMap值会覆盖掉任务实例的值

/**
 * @Author ScholarTang
 * @Date 2021/7/13 10:45
 * @Desc 任务类
 */
@Slf4j
public class HelloJob implements Job {

    private String message;
    private String username;

    public void setMessage(String message) {
        this.message = message;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //通过JobExecutionContext获取JobDetail
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobKey jobKey = jobDetail.getKey();
        String jobDetailName = jobKey.getName();
        String jobDetailGroup = jobKey.getGroup();
        String jobClazzNameJobDetail = jobKey.getClass().getName();
        log.info("任务实例的唯一标识名称:" + jobDetailName);
        log.info("任务实例的组名:" + jobDetailGroup);
        log.info("任务实例绑定的任务类信息:" + jobClazzNameJobDetail);
        log.info("-----------------------------------------");
        //通过JobExecutionContext获取Trigger
        Trigger trigger = jobExecutionContext.getTrigger();
        TriggerKey triggerKey = trigger.getKey();
        String triggerKeyName = triggerKey.getName();
        String triggerKeyGroup = triggerKey.getGroup();
        String triggerClazzName = triggerKey.getClass().getName();
        log.info("触发器的唯一标识名称:" + triggerKeyName);
        log.info("触发器的组名:" + triggerKeyGroup);
        log.info("触发器绑定的任务类信息:" + triggerClazzName);
        log.info("-----------------------------------------");
        //通过JobExecutionContext
        String jobClazzName = jobExecutionContext.getClass().getName();
        log.info("job类相关的信息:"+jobClazzName);
        log.info("-----------------------------------------");
        //获取JobDetail中JobDataMap中的message内容
        //JobDataMap jobDataMap = jobDetail.getJobDataMap();
        //String message = jobDataMap.getString("message");
        log.info("从JobDetail-JobDataMap中或到的message内容为:" + message);
        //获取Trigger中JobDataMap中的username内容
        //JobDataMap triggerJobDataMap = trigger.getJobDataMap();
        //String username = triggerJobDataMap.getString("username");
        log.info("从Trigger-JobDataMap中获取到的username内容为:" + username);
        log.info("-----------------------------------------");
        log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) + " | 任务被执行了");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nDzE23Rv-1626662449863)(\images\image-20210713143046337.png)]

3.3.获取其他
//获取任务的本次执行时间
Date fireTime = jobExecutionContext.getFireTime();
//获取任务的下次执行时间
Date nextFireTime = jobExecutionContext.getNextFireTime();

log.info("任务的本次执行时间:" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(fireTime));
log.info("任务的下次执行时间:" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(nextFireTime));

4.有状态的Job和无状态的Job

什么是有状态的Job?什么是无状态的Job?

有状态的Job可以理解为多次Job调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,而默认的无状态Job每次调用时都会创建一个新的JobDataMap

4.1.Job默认是无状态的,通过如下示例查看:
package com.scholartang.quartz.main;

import com.scholartang.quartz.job.HelloJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.triggers.CoreTrigger;

/**
 * @Author ScholarTang
 * @Date 2021/7/13 10:53
 * @Desc 调度器
 */
@Slf4j
public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        //从调度工厂中获取调度器实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //通过JobBuilder构建一个任务实例
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                //设置任务的唯一实例名称和任务组名称组名
                .withIdentity("job1", "group1")
                //设置jobDataMap数据   <<===============
                .usingJobData("count",0)
                //构建实例
                .build();
        //通过TriggerBuilder构建触发器实例
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                //设置触发器唯一实例名称和触发器的组名
                .withIdentity("trigger1", "group1")
                //执行计划,每五秒执行一次
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
                //立即执行
                .startNow()
                //构建实例
                .build();
        //调度器绑定任务实例和触发器
        scheduler.scheduleJob(jobDetail,trigger);
        //开启定时任务
        scheduler.start();
    }
}

/**
 * @Author ScholarTang
 * @Date 2021/7/13 10:45
 * @Desc 任务类
 */
@Slf4j
public class HelloJob implements Job {
    private Integer count;

    public void setCount(Integer count) {
        this.count = count;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //通过JobExecutionContext获取JobDetail
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        count++;
        jobDetail.getJobDataMap().put("count",count);
        log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) + " | 任务被执行了");
        log.info("当前count的值为:" + count);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pq9NPM4D-1626662449864)(\images\image-20210713145605765.png)]

4.2.通过@PersistJobDataAfterExecution注解将Job设置为由状态的
/**
 * @Author ScholarTang
 * @Date 2021/7/13 10:45
 * @Desc 任务类
 */
@Slf4j
@PersistJobDataAfterExecution
public class HelloJob implements Job {
    private Integer count;

    public void setCount(Integer count) {
        this.count = count;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //通过JobExecutionContext获取JobDetail
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        count++;
        jobDetail.getJobDataMap().put("count",count);
        log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) + " | 任务被执行了");
        log.info("当前count的值为:" + count);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VZgRp2NC-1626662449866)(\images\image-20210713145844114.png)]

如果Job类没有添加@PersistJobDataAfterExecution注解,每次调用时都会创建一个新的JobDataMap。不会累加count的值
如果Job类添加了@PersistJobDataAfterExecution注解,每次调用期间都会持有一些状态信息,。会累加count的值

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值