java任务调度框架Quartz

背景

为什么需要任务调度框架:

  1. 账单日或者还款日上午 10 点,给每个信用卡客户发送账单通知,还款通知。如何判断客户的账单日、还款日,完成通知的发送?
  2. 对于后台一些数据迁移、任务跑批等需要定时执行。

类似基于这种:基于准确的时刻或者类似的时间间隔触发的任务、批量数据处理、要实现两个动作解耦的场景,我们都可以用任务调度来实现。

我们对任务调度框架的基本需求:

  • 可以定义触发规则,比如基于时刻、时间间隔、表达式等。
  • 可以定义需要执行的任务,比如执行一个脚本或者一段代码,任务和规则分开。
  • 集中管理配置、持久化配置,不用把配置写在代码里面,可以看到所以任务配置,方便维护,重启之后任务可以再次调度。
  • 支持任务的串行执行。
  • 有自己调度器,可以运行、停止、中断任务。
  • 容易集成到spring。

任务调度跨框架对比:

层次举例特点
操作系统Linux Crontab、windows计划任务只能执行简单脚本或者命令
数据库MySQL、Oracle可以操作数据,不能执行java代码
工具Kettle可以操作数据、执行脚本、没有集中配置
开发语言JDK Timer、 ScheduledThreadPoolTimer: 单线程,也就是任务的执行是串行的。JDK1.5 之后: ScheduledThreadPool(Cache、 Fiexed、Single) :没有集中配置, 日程管理不够灵活
容器Spring Task、 @Scheduled不支持集群、实现不了负载和高可用
分布式任务调度框架XXL-JOB, Elastic-Job
quartz

Quartz 的意思是石英,像石英表一样精确。Quartz 是一个老牌的任务调度系统,98 年构思,01 年发布到 sourceforge。现在更新比较慢,因为已经非常成熟了。
官网:http://www.quartz-scheduler.org/
GitHub地址:https://github.com/quartz-scheduler/quartz

Quartz 的目的就是让任务调度更加简单,开发人员只需要关注业务即可。他是用 Java 语言编写的(也有.NET 的版本)。Java 代码能做的任何事情,Quartz 都可以调度。

特点:

  1. 精确到毫秒级别的调度。
  2. 可以独立运行,也可以集成到容器中。
  3. 支持事务(JobStoreCMT )。
  4. 支持集群。
  5. 支持持久化。
Quartz Java 编程

依赖:

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

默认配置文件:
org.quartz包下,有一个默认的配置文件,quartz.properties。当我们没有定义一个同名的配置文件的时候,就会使用默认配置文件里面的配置。
在这里插入图片描述


org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true

org.quartz.jobStore.misfireThreshold: 60000

org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

Quartz体系结构:
在这里插入图片描述

JobDetail

我们创建一个实现 Job 接口的类,使用 JobBuilder 包装成 JobDetail,它可以携带
KV 的数据(通过JobDataMap)用于扩展属性,在运行的时候可以从 context获取到,然后通过name+group唯一确定一个JobDetail。

Trigger

定时任务的触发规则(触发器),定义了任务调度的触发时机,使用TriggerBuilder 构建,与JobDetail是N:1的关系,也就是一个JobDetail可以对应多个触发器。两者之间解耦,也就是任务与触发时机解耦,通过scheduler进行调控。

Trigger接口有四个子接口,代表四种类型的触发器。

子接口描述特点
SimpleTrigger简单触发器可以设置固定的时刻或者时间间隔触发,单位毫秒
CalendarIntervalTrigger基于日历的触发器比简单触发器更多时间单位,支持非固定时间的触发, 例如一年可能 365/366, 一个月可能 28/29/30/31
DailyTimeIntervalTrigger基于日期的触发器每天的某个时间段
CronTrigger基于cron表达式的触发器基于cron表达式,十分的灵活,实际上可以代替上面的触发器

在这里插入图片描述

SimpleTrigger:
SimpleTrigger 可以定义固定时刻或者固定时间间隔的调度规则(精确到毫秒)。

CalendarIntervalTrigger:
CalendarIntervalTrigger 可以定义更多时间单位的调度需求,精确到秒。
好处是不需要去计算时间间隔,比如 1 个小时等于多少毫秒。
例如每年、每个月、每周、每天、每小时、每分钟、每秒。
每年的月数和每个月的天数不是固定的,这种情况也适用。

DailyTimeIntervalTrigger:
每天的某个时间段内,以一定的时间间隔执行任务。
例如:每天早上 9 点到晚上 9 点,每隔半个小时执行一次,并且只在周一到周六执行。

CronTrigger:
CronTirgger 可以定义基于 Cron 表达式的调度规则,是最常用的触发器类型。

Scheduler

调度器,是 Quartz 的指挥官,由 StdSchedulerFactory 产生。它是单例的。并且是 Quartz 中最重要的 API,默认是实现类是 StdScheduler,里面包含了一个QuartzScheduler。QuartzScheduler 里面又包含了一个 QuartzSchedulerThread(调度线程池)。
Scheduler中的方法分为三大类:
1)操作调度器本身,例如调度器的启动 start()、调度器的关闭 shutdown()。
2)操作 Trigger,例如 pauseTriggers()、resumeTrigger()。
3)操作 Job,例如 scheduleJob()、unscheduleJob()、rescheduleJob()

Listener

我们有这么一种需求,在每个任务运行结束之后发送通知给运维管理员。那是不是要在每个任务的最后添加一行代码呢?这种方式对原来的代码造成了入侵,不利于维护。如果代码不是写在任务代码的最后一行,怎么知道任务执行完了呢?或者说,怎么监测到任务的生命周期呢?那就需要Listener来监控任务的生命周期。
Quartz 中提供了三种 Listener,监听 Scheduler 的,监听 Trigger 的,监听 Job 的。
只需要创建类实现相应的接口,并在 Scheduler 上注册 Listener,便可实现对核心对象的监听。

JobStore

Jobstore 用来存储任务和触发器相关的信息,例如所有任务的名称、数量、状态等等。Quartz 中有两种存储任务的方式,一种在在内存(RAMJobStore),一种是在数据库(JDBCJobStore)。

实战
//任务的定义
/**
 * @author YeHaocong
 * @decription 任务定义、实现Job接口,重写execute方法,这个就是任务调度时执行的逻辑。
 */

public class MyJobDemo1 implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //JobExecutionContext是上下文,可以获取KV信息、触发器等信息。
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        System.out.println( " " + sf.format(date) + " 任务1执行了," + dataMap.getString("jobName"));
    }
}
//触发器的定义
//触发器的类型要靠ScheduleBuilder的类型来区分

//创建一个SimpleTrigger
public Trigger getSimpleTrigger(){
	 Trigger simpleTrigger = TriggerBuilder.newTrigger()
                //设置开始时间
                .startAt(new Date())
                //设置额外信息
                .usingJobData("tName","simpleTrigger")
                //设置触发器的id
                .withIdentity("simpleTrigger","triggerGroup")
                //描述
                .withDescription("这是简单触发器")
                //设置触发条件,这里使用SimpleScheduleBuilder,意味着创建的是simpleTrigger,触发条件是3秒一次且永远重复
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3))
                //立即启用触发器
                .startNow()
                //创建
                .build();
      return simpleTrigger;
}


//创建一个CalendarIntervalTrigger
public Trigger getCalendarIntervalTrigger(){
	 Trigger calendarIntervalTrigger = TriggerBuilder.newTrigger()
                //定义额外参数
                .usingJobData("tName","CalendarIntervalTrigger")
                //使用name和group唯一确定这个触发器
                .withIdentity("CalendarIntervalTrigger","triggerGroup")
                //描述
                .withDescription("这是基于日历的触发器")
                //每分钟执行一次
                .withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInMinutes(1))
                //立即启动
                .startNow()
                .build();
         return calendarIntervalTrigger;
}

//创建一个DailyTimeIntervalTrigger
public Trigger  getDailyTimeIntervalTrigger(){
        Trigger dailyTimeIntervalTrigger = TriggerBuilder.newTrigger()
                //设置为星期六星期天
                .withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule().onSaturdayAndSunday())
                .build();
        return dailyTimeIntervalTrigger;
    }

//创建cronTrigger
public Trigger  getCronTrigger(){
        Trigger dailyTimeIntervalTrigger = TriggerBuilder.newTrigger()
                //设置为每5秒执行一次
                .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))
                .build();
        return dailyTimeIntervalTrigger;
    }
//使用scheduler来实现一次任务调度
/**
 * @author YeHaocong
 * @decription TODO
 */

public class MyScheduler {
    public static void main(String[] args) throws SchedulerException {

        //创建任务
        JobDetail jobDetail = JobBuilder.newJob(MyJobDemo1.class)
                .usingJobData("jobName","MyJobDemo1")
                .withIdentity("MyJobDemo1","jobGroup")
                .build();

        //创建简单触发器。每分钟执行一次

        Trigger simpleTrigger = TriggerBuilder.newTrigger()
                //定义额外参数
                .usingJobData("tName","simpleTrigger")
                //使用name和group唯一确定这个触发器
                .withIdentity("simpleTrigger","triggerGroup")
                //描述
                .withDescription("简单触发器")
                //每分钟执行一次
                .withSchedule(SimpleScheduleBuilder.repeatMinutelyForever())
                //立即启动
                .startNow()
                .build();

        //创建CalendarIntervalTrigger,每两分钟执行一次
        Trigger CalendarIntervalTrigger = TriggerBuilder.newTrigger()
                //定义额外参数
                .usingJobData("tName","CalendarIntervalTrigger")
                //使用name和group唯一确定这个触发器
                .withIdentity("CalendarIntervalTrigger","triggerGroup")
                //.forJob(jobDetail)
                //.forJob(jobDetail2)
                //描述
                .withDescription("这是基于日历的触发器")
                //每2分钟执行一次
                .withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInMinutes(2))
                //立即启动
                .startNow()
                .build();

        //把两个触发器加入到一个集合里面
        Set<Trigger> triggers = new HashSet<>();
        triggers.add(CalendarIntervalTrigger);
        triggers.add(simpleTrigger);

        //创建一个调度器工厂
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        //获取调度器,单例模式的,获取的调度器都一样
        Scheduler scheduler = schedulerFactory.getScheduler();

        //添加任务和触发器  这个就是 1个任务对应2个触发器   第三个参数是是否代替的意思,就是如果存在同名、同组任务或者触发器时,是否用这个覆盖。
        scheduler.scheduleJob(jobDetail,triggers,false);
        //启动任务调度
        scheduler.start();
    }
}

结果:
在这里插入图片描述
18.40.19因为两个触发器都执行了,18.41.19是简单触发器触发,因为他是一分钟间隔。18.42.19两个触发,合情合理。

基于 Calendar 的排除规则

如果要在触发器的基础上,排除一些时间区间(比如圣诞节、春节等等)不执行任务,就要用到 Quartz 的Calendar 类(注意不是 JDK 的 Calendar)。可以按年、月、周、日、特定日期、Cron表达式排除。

  • BaseCalendar:为高级的 Calendar 实现了基本的功能, 实现了 org.quartz.Calendar 接口。
  • AnnualCalendar:排除年中一天或多天
  • CronCalendar :cron的这种实现排除了由给定的 CronExpression 表达的时间集合。 比如使用* * 0-7,18-23 ? * * 就排除每天0-7 18-23 这段时间,只在8-17这段时间剩下。如果 CronTrigger 具有给定的 cron 表达式并且与具有相同表达式的 CronCalendar 相冲突, 则将排除触发器包含的所有时间, 并且它们将彼此抵消。也就是假如排除每天8-15时,然后CronTrigger 设置的规则是8-16时每五秒执行一次,最后的结果是16时每5秒执行一次,8-15被排除了。取CronTrigger 的补集。
  • DailyCalendar:可以使用此日历来排除营业时间(上午 8 点 - 5 点) 每天。 每个DailyCalendar 仅允许指定单个时间范围, 并且该时间范围可能不会跨越每日边界(即, 不能指定从上午 8 点至凌晨 5 点的时间范围) 。 如果属性 invertTimeRange 为 false(默认) , 则时间范围定义触发器不允许触发
    的时间范围。 如果 invertTimeRange 为 true, 则时间范围被反转 - 也就是排除在定义的时间范围之外的所有时间。
  • HolidayCalendar:特别的用于从 Trigger 中排除节假日。
  • MonthlyCalendar :排除月份中的指定数天, 例如, 可用于排除每月的最后一天。
  • WeeklyCalendar:排除星期中的任意周几, 例如, 可用于排除周末, 默认周六和周日

调用 Trigger 的 modifiedByCalendar()添加到触发器中,并且调用调度器的addCalendar()方法注册排除规则。
modifiedByCalendar只能一次,也就是一个触发器只能modifiedByCalendar一个Calendar,否则如果多个,后面会覆盖前面,最终只有最后一个modifiedByCalendar的Calendar起效果。

public class MyScheduler2 {

    public static void main(String[] args) throws SchedulerException {
        AnnualCalendar annualCalendar = new AnnualCalendar();
        //定义国庆节
        Calendar calendar = new GregorianCalendar(2021,10,1);
        //排除国庆节
        annualCalendar.setDayExcluded(calendar,true);

        //排除8-17点
        DailyCalendar dailyCalendar = new DailyCalendar("08:00:00","17:59:59");


        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.addCalendar("annualCalendar",annualCalendar,false,false);

		JobDetail jobDetail = JobBuilder.newJob(MyJobDemo1.class)
                .withIdentity("job1", "group1")
                .usingJobData("name","job")
                .build();

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                //添加规则到触发器
                .modifiedByCalendar("annualCalendar")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())
                .build();
    }
}


Listener
JobListener

首先定义一个类实现JobListener,并实现他的生命周期方法。并用ListenerManager对象对监听器进行添加、移除、获取。

Matcher,主要是基于 groupName 和 keyName 进行匹配。

//实现的listener类
public class MyJobListener implements JobListener {


    @Override
    public String getName() {
        String name = getClass().getSimpleName();
        System.out.println( "Method 111111 :"+ "获取到监听器名称:"+name);
        return name;
    }
    @Override
    //任务即将执行时调用
    public void jobToBeExecuted(JobExecutionContext context) {
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Method 222222 :"+ jobName + " ——任务即将执行 ");
    }
    @Override
    //Scheduler 在 JobDetail 即将被执行, 但又被 TriggerListener 否决了时调用这个
方法
    public void jobExecutionVetoed(JobExecutionContext context) {
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Method 333333 :"+ jobName + " ——任务被否决 ");
    }
    @Override
    //任务执行完毕时调用
    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Method 444444 :"+ jobName + " ——执行完毕 ");
        System.out.println("------------------");
    }
}

//测试类
public class JobListenerTest {

    public static void main(String[] args) throws SchedulerException {
        // JobDetail
        JobDetail jobDetail = JobBuilder.newJob(MyJobDemo1.class).withIdentity("job1", "group1").build();

        // Trigger
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();

        // SchedulerFactory
        SchedulerFactory  factory = new StdSchedulerFactory();

        // Scheduler
        Scheduler scheduler = factory.getScheduler();

        scheduler.scheduleJob(jobDetail, trigger);

        // 创建并注册一个全局的Job Listener
        scheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());

        scheduler.start();
    }
}
TriggerListener

这里接不写代码了,直接说明生命周期方法。

方法描述
getName()获取监听器名称
triggerFired()Trigger 被触发, Job 上的 execute() 方法将要被执行时, Scheduler 就调用这个方法
vetoJobExecution()在 Trigger 触 发 后 , Job 将 要 被 执 行 时 由 Scheduler 调 用 这 个 方 法 。TriggerListener 给了一个选择去否决 Job 的执行。 假如这个方法返回 true, 这个 Job 将不会为此次 Trigger 触发而得到执行,就是如果该方法返回true,代表这个任务不会被执行
triggerMisfired()Trigger 错过触发时调用
triggerComplete()Trigger 被触发并且完成了 Job 的执行时, Scheduler 调用这个方法
SchedulerListener
方法描述
jobScheduled(Trigger trigger)调用scheduledJob方法成功的回调
jobUnscheduled(TriggerKey triggerKey)调用unscheduleJob方法成功的回调
triggerFinalized(Trigger trigger)触发器触发完成的回调
triggerPaused(TriggerKey triggerKey)调用pauseTrigger方法成功的回调
triggersPaused(String triggerGroup)调用pauseTriggers方法成功的回调
triggerResumed(TriggerKey triggerKey)调用resumeTrigger方法成功的回调
triggersResumed(String triggerGroup)调用resumeTriggers方法成功的回调
jobAdded(JobDetail jobDetail)调用addJob方法成功的回调
jobDeleted(JobKey jobKey)调用deleteJob方法成功的回调
jobPaused(JobKey jobKey)调用pauseJob方法成功的回调
jobsPaused(String jobGroup)调用pauseJobs方法成功的回调
jobResumed(JobKey jobKey)调用resumeJob方法成功的回调
jobsResumed(String jobGroup)调用resumeJobs方法成功的回调
schedulerError(String msg, SchedulerException cause)scheduler调用方法出现异常时的回调
schedulerInStandbyMode()调用standby方法成功的回调
schedulerStarted()scheduler启动后的回调
schedulerStarting()scheduler启动时的回调
schedulerShutdown()scheduler关闭的回调
schedulerShuttingdown()scheduler关闭时的回调
schedulingDataCleared()调用clear方法的回调
API列表

TriggerBuilder:


//这个类用于构建Trigger

//创建一个TriggerBuilder
public static TriggerBuilder<Trigger> newTrigger()

//最终创建一个触发器
public T build()

//定义触发器名字,group使用null。
public TriggerBuilder<T> withIdentity(String name)

//配置触发器name和group,这两个唯一确定一个触发器
public TriggerBuilder<T> withIdentity(String name, String group)

//使用TriggerKey 配置触发器的name和group,TriggerKey 是对name和group的封装
public TriggerBuilder<T> withIdentity(TriggerKey triggerKey)

//定义触发器的描述信息
public TriggerBuilder<T> withDescription(String triggerDescription)

//触发器的优先级,如果多个触发器在同一时间触发,优先给优先级高的触发器分配线程调度。数字越大,优先级越高
public TriggerBuilder<T> withPriority(int triggerPriority)

//添加Calendar日期规则,要配合scheduler的addCalendar()使用,也就是Trigger添加的Calendar必须要在scheduler的addCalendar()添加过。
public TriggerBuilder<T> modifiedByCalendar(String calName)

//从什么时间开始
public TriggerBuilder<T> startAt(Date triggerStartTime)

//立即启用调度器
public TriggerBuilder<T> startNow()

//从什么时候结束,比如从8点开始、10点结束,期间每10分钟执行一次。
public TriggerBuilder<T> endAt(Date triggerEndTime)

//设置调度规则,ScheduleBuilder的类型配合TriggerBuilder的泛型决定Trigger的类型。
public <SBT extends T> TriggerBuilder<SBT> withSchedule(ScheduleBuilder<SBT> schedBuilder)

//添加任务,可以执行多次,但是只有最后一个生效,因为任务和触发器时一对多,一个触发器只能对应一个任务。
//还有一些重载方法,这里就不列出来了。
//这里添加的任务必须要在调度器scheduler中调用addJob添加的任务列表内才行,不然报错。
public TriggerBuilder<T> forJob(JobKey keyOfJobToFire)

//添加k/V参数到触发器,可调用多次。其他重载方法就不列出来了
public TriggerBuilder<T> usingJobData(String dataKey, String value)

ScheduleBuilder:

//调度规则构建器,有四个实现类,分别代表四种触发器。
//CalendarIntervalScheduleBuilder:CalendarIntervalTrigger
//CronScheduleBuilder:CronTrigger
//DailyTimeIntervalScheduleBuilder:DailyTimeIntervalTrigger
//SimpleScheduleBuilder:SimpleTrigger

//这四个的具体API就省略了,因为十分能见名知意,根据方法名就能知道啥意思。

JobBuilder:

//该类用于构建JobDetail
//创建一个JobBuilder 对象
public static JobBuilder newJob()

//newJob()+ofType   创建一个JobBuilder 并指定任务的类型,也就是我们实现了Job的自定义类对象。
public static JobBuilder newJob(Class <? extends Job> jobClass)

//最终创建一个JobDetail 
public JobDetail build()

//设置任务身份信息,group为null。
public JobBuilder withIdentity(String name)

//设置任务身份信息,设置name+group
public JobBuilder withIdentity(String name, String group)

//设置任务身份信息,JobKey 是name和group的封装。
public JobBuilder withIdentity(JobKey jobKey)

//设置描述信息
public JobBuilder withDescription(String jobDescription)

//设置JobDetail的任务类型
public JobBuilder ofType(Class <? extends Job> jobClazz)

//指示调度器,当任务调用过程中出现故障转移或者恢复时,是否重新执行任务,默认false,这个方法就是把它设置为true。
public JobBuilder requestRecovery()

//直接指定true或者false。
public JobBuilder requestRecovery(boolean jobShouldRecover)

//当该任务没有被触发器指定时或者跟触发器绑定时,是否进行持久化,默认false,这个方法设置为true。
 public JobBuilder storeDurably()

//这个方法可以设置true和false。
public JobBuilder storeDurably(boolean jobDurability)

//配置额外KV信息,其他重载方法不列出。
public JobBuilder usingJobData(String dataKey, String value)

//usingJobData是在原本的基础上添加,这个方法是直接替换原本的。
public JobBuilder setJobData(JobDataMap newJobDataMap)

scheduler:

//调度器,赋值调控trigger和job,使得他们解耦
//获取调度器名称
String getSchedulerName()

//获取调度器id
String getSchedulerInstanceId()

//获取调度器的上下文,包括调控的触发器、任务等等信息。
SchedulerContext getContext()

//启动
void start()

//调度器延迟多少秒后才启动
 void startDelayed(int seconds)

//返回调度器是否已经启动
boolean isStarted()

//把调度器状态设置为就绪状态,相当于停止状态,此状态的调度器不会工作。此状态下的调度器可以随时重新启动工作。
//该状态下的调度器会记录在该状态期间理应触发的触发器,但是因为在该状态下,不能工作,所以会把它们记录下来,等待重新启动时会补执行。
void standby()

//返回是否调度器是否处于standby状态。
boolean isInStandbyMode()

//关闭调度器,关闭后就不能再次重新启动。默认不等待任务执行完成,直接返回。
void shutdown()

//关闭调度器,waitForJobsToComplete如果设置为true,那么该方法会阻塞直到执行完全部正在执行的任务后再返回。上面的 shutdown()的waitForJobsToComplete为false。直接返回。
void shutdown(boolean waitForJobsToComplete)

//返回是否已关闭
boolean isShutdown()

//获取调度器元信息
SchedulerMetaData getMetaData()

//获取当前正在执行的任务列表。
getCurrentlyExecutingJobs()

//设置JobFactory 
void setJobFactory(JobFactory factory)

//获取该调度器的监听器管理器,用于添加、移除、获取监听器
ListenerManager getListenerManager()

//调度任务1对1
Date scheduleJob(JobDetail jobDetail, Trigger trigger)

//调度任务,配合addjob + trigger.forjob使用。
Date scheduleJob(Trigger trigger)

//调度任务,1对多,一个任务对多个触发器,replace表示存在同名触发器或者任务时,是否覆盖。
void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) 

//调度任务1对多
void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace)

//移除触发器
boolean unscheduleJob(TriggerKey triggerKey)
//移除多个触发器
 boolean unscheduleJobs(List<TriggerKey> triggerKeys)
//移除triggerKey触发器,设置newTrigger触发器
Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) 

//添加任务,replace同名是否覆盖
void addJob(JobDetail jobDetail, boolean replace)

//添加任务,storeNonDurableWhileAwaitingScheduling
void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling)

//删除任务
boolean deleteJob(JobKey jobKey)

//删除多个任务
boolean deleteJobs(List<JobKey> jobKeys)

//立即执行某个任务
void triggerJob(JobKey jobKey)

//立即执行某个任务,可以设置额外信息
void triggerJob(JobKey jobKey, JobDataMap data)

//停止任务,通过停止他所有的关联触发器实现的。
void pauseJob(JobKey jobKey)

//通过一定组规则停止任务
void pauseJobs(GroupMatcher<JobKey> matcher)

//停止触发器
void pauseTrigger(TriggerKey triggerKey)

//通过一定组规则停止触发器
void pauseTriggers(GroupMatcher<TriggerKey> matcher)

//重新启动被 pause的任务,会记录在停止期间错过的执行次数,恢复时会补执行。
void resumeJob(JobKey jobKey)

//根据组规则恢复任务
void resumeJobs(GroupMatcher<JobKey> matcher)

//恢复触发器,会记录在停止期间错过的执行次数,恢复时会补执行。
 void resumeTrigger(TriggerKey triggerKey)

//根据组规则恢复触发器
void resumeTriggers(GroupMatcher<TriggerKey> matcher)

//停止所有触发器
void pauseAll()

//恢复所有触发器
void resumeAll()

//获取任务组名列表
List<String> getJobGroupNames()

//获取某个组的任务集合
Set<JobKey> getJobKeys(GroupMatcher<JobKey> matcher) 

//获取任务关联的触发器列表
List<? extends Trigger> getTriggersOfJob(JobKey jobKey)

//获取某个组的触发器列表
List<String> getTriggerGroupNames()

//获取被停止的触发器组集合
Set<String> getPausedTriggerGroups()

//获取JobDetail 
JobDetail getJobDetail(JobKey jobKey)

//获取触发器
Trigger getTrigger(TriggerKey triggerKey)

//获取触发器状态。
//六个状态NONE, NORMAL(正常状态), PAUSED(停止状态), COMPLETE(已完成), ERROR(出错), BLOCKED(阻塞)
TriggerState getTriggerState(TriggerKey triggerKey)

//将指定触发器把状态从ERROR改为NORMAL或者PAUSED
void resetTriggerFromErrorState(TriggerKey triggerKey)

//
//添加日期规则,replace同名是否覆盖,updateTriggers是否更新已经有了日期规则的触发器,使其使用新添加的规则。
void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)

//删除日期规则
boolean deleteCalendar(String calName)

//根据名字获取规则
 Calendar getCalendar(String calName)

//获取日期规则列表
List<String> getCalendarNames()

//中断某个任务
boolean interrupt(JobKey jobKey)
//返回任务是否存在
boolean checkExists(JobKey jobKey)

//返回触发器是否存在
boolean checkExists(TriggerKey triggerKey)

//清除所有东西,包括触发器、任务、日期规则等等。
void clear()
持久化

Jobstore 用来存储任务和触发器相关的信息,例如所有任务的名称、数量、状态等等。Quartz 中有两种存储任务的方式,一种在在内存,一种是在数据库。

RAMJobStore

quartz 默认的 JobStore 是 RAMJobstore,也就是把任务和触发器信息运行的信息存储在内存中,用到了 HashMap、TreeSet、HashSet 等等数据结构。如果程序崩溃或重启,所有存储在内存中的数据都会丢失。所以我们需要把这些数据持久化到磁盘。

JDBCJobStore

JDBCJobStore 可以通过 JDBC 接口,将任务运行数据保存在数据库中。
JDBC 的实现方式有两种,JobStoreSupport 类的两个子类:
JobStoreTX:在独立的程序中使用(专门的任务调度系统),自己管理事务,不参与外部事务。
JobStoreCMT:(Container Managed Transactions (CMT),如果需要容器管理事务时,使用它。

需要配置数据库信息,在类路径的quartz.properties文件中配置。

#使用的JobStoreTX实现
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
#指定的代理类
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 使用 quartz.properties, 不使用默认配置
org.quartz.jobStore.useProperties:true
#数据库中 quartz 表的表名前缀
org.quartz.jobStore.tablePrefix:QRTZ_
#数据源 ,在下面配置
org.quartz.jobStore.dataSource:myDS
​
#配置数据源
org.quartz.dataSource.myDS.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL:jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf8
org.quartz.dataSource.myDS.user:root
org.quartz.dataSource.myDS.password:123456
org.quartz.dataSource.myDS.validationQuery=select 0 from dual

表结构从jar包的org.quartz.impl.jdbcjobstore包中可以获得:我们选择mysql相关建表语句。
在这里插入图片描述

表的含义:

表名作用
QRTZ_BLOB_TRIGGERSTrigger 作为 Blob 类型存储
QRTZ_CALENDARS存储 Quartz 的 Calendar 信息
QRTZ_CRON_TRIGGERS存储 CronTrigger, 包括 Cron 表达式和时区信息
QRTZ_FIRED_TRIGGERS存储与已触发的 Trigger 相关的状态信息, 以及相关 Job 的执行信息
QRTZ_JOB_DETAILS存储每一个已配置的 Job 的详细信息
QRTZ_LOCKS存储程序的悲观锁的信息
QRTZ_PAUSED_TRIGGER_GRPS存储已暂停的 Trigger 组的信息
QRTZ_SCHEDULER_STATE存储少量的有关 Scheduler 的状态信息, 和别的 Scheduler 实例
QRTZ_SIMPLE_TRIGGERS存储 SimpleTrigger 的信息, 包括重复次数、 间隔、 以及已触的次数
QRTZ_SIMPROP_TRIGGERS存储 CalendarIntervalTrigger 和 DailyTimeIntervalTrigger 两种类型的触发器
QRTZ_TRIGGERS存储已配置的 Trigger 的信息

验证:

在这里插入图片描述
执行一次调度后,就把相关信息持久化到数据库的表中。

与spring的集成

就是配置bean而已,Spring 在 spring-context-support.jar 中直接提供了对 Quartz 的支持。
如果是基于xml配置的话:需要配置以下对象代替原本的。
org.springframework.scheduling.quartz.JobDetailFactoryBean //JobDetail
org.springframework.scheduling.quartz.SimpleTriggerFactoryBean //简单触发器
org.springframework.scheduling.quartz.SchedulerFactoryBean //调度器

如果使用的是java配置类的话,就跟使用原生那样配置就可以了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值