Quartz

发布于 2022-10-19  4.23k 次阅读


1. Quartz的基本介绍

1.1 Quartz的概念

    Quartz是OpenSymphony开源组织在job scheduling领域的开源项目(定时任务调度框架),它开源集成到J2EE进二J2SE应用程序,也可以进行单独使用

Quartz任务调度框架的官方定义:

  • quartz是一个开源且特性丰富的"任务调度库",那个集成到任何java程序中,小到独立的应用,大到电子商城系统
  • quartz能够创建亦简单亦复杂的调度,可以执行甚至上万的任务调度
  • 任务job被定义为标准的java组件,能够执行任何需求功能,
  • quartz调度框架包含许多企业级的特性,如:AT事物,集群的支持

Quartz的开发应用场景:

  • 定时任务的调度
  • 循环任务的调度

简而言之Quartz就是基于java开发的任务调度框架

1.2 Quartz的运行环境

Quartz可以在四种环境下运行:

  • Quartz可以运行嵌入在另一个独立式应用程序中
  • Quartz可以在应用程序服务器(或servlet容器)内被实例化,并参与事物
  • Quartz可以做为一个独立的程序运行(其自己的java),可以通过RMI使用
  • Quartz可以被实例化,做为独立的项目集群(负载平衡和故障转移功能),用于作业的执行

Quartz使用到的设计模式:

  • Builder模式(创建者模式)
  • Factory模式(工厂模式)
  • 组件模式
  • 链式编程

2. Quartz的核心概念与API

2.1 Quartz的核心概念

Quartz的四大核心概念:

1,任务job:

  • job就是想要实现的任务类,每一个job必须实现org.quartz.job接口,且只需实现接口定义的execute()方法

2,任务信息JobDetall

  • JobDetail实例是在将job加入scheduler时,由客户端程序(你的程序)创建的。它包含job的各种属性设置,以及用于存储job实例状态信息的JobDataMap

3,触发器Trigger:

  • Trigger为实现执行任务的触发器,比如你想每周一定时8点进行数据库备份,Trigger将会设置3点进行执行该任务
  • Trigger主要包含SimpleTrigger和CronTrigger两种,且有不同的应用场景

4,调度器Scheduler:

  • Scheduler为任务的调度器,它会将任务job及触发器trigger两种进行整合,负责Trigger设定时间来执行job

 Quartz体系结构图:

2.2 Quartz的常用组件API

以下是Quartz编程API几个重要接口组件:

  1. Scheduler:用于调度程序交互的主程序接口
  2. job:预先定义希望在未来时间能够被调度程序执行的任务类
  3. jobDerail:定义job任务的基本信息,通过JobBuilder类创建
  4. jobDataMap:可以包含不限量的序列化数据对象,在Job实例执行的时候,可以使用其中的数据;JobDataMap是Java Map接口的实现,额外的增加了一些存取的基本类型方法
  5. Trigger:触发执行Job,当调度一个job时,外面实例一个触发器调整它们的属性来满足job执行的条件,定义一个任务在什么时候执行和执行次数
  6. JobBuilder:用于声明一个任务实例,也可以定义关于该任务的详情比如任务名、组名等,这个声明的实例将会作为一个实际执行的任务
  7. TriggerBuilder:触发器创建器,用于创建触发器trigger实例
  8. JobListener、TriggerListener、SchedulerListener监听器,用于对组件的监听

3. Quartz初体验

导入maven依赖:

<!--quartz核心包-->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>

<!--quartz jo工具包-->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.3.2</version>
</dependency>

① 任务类型

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        //打印当前日期和数据
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateformat = simpleDateFormat.format(date);

        //执行任务
        System.out.println(dateformat+"--数据库备份!!");
    }
}

② 调度

//1,调度器(Scheduler),从工厂中获取调度实例
Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();

//2,任务实例(JobDetail)
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//加载任务类
        .withIdentity("job1", "group1")//参数1:任务的名称 参数2:任务组的名称
        .build();

//3,触发器(Trigger)
SimpleTrigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("trigger1", "group1")//参数1:触发器名称 参数2:触发器组名称
        .startNow()//启动后立即执行触发器
        .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(7))//每七秒执行重复执行一次
        .build();

//Scheduler调度器关联任务实例和触发器,保证触发器定义的条件执行任务实例
defaultScheduler.scheduleJob(jobDetail,trigger);

//启动调度器
defaultScheduler.start();

结果:

2022-10-12 16:58:18--数据库备份!!
2022-10-12 16:58:25--数据库备份!!
2022-10-12 16:58:32--数据库备份!!
2022-10-12 16:58:39--数据库备份!!

4. 各组件说明

4.1 Job和JonDetail的说明

Job和JobDetail的作用:

  • Job:工作任务调度的接口,任务类需要实现该接口。该接口中定义execute方法,类似于JDK提供的Runable类的run方法。在里面编写业务逻辑
  • JobDetail:JobDetail为Job实例类提供了许多属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助obDetail对象来添加Job实例

Job实例在Quartz中的生命周期:

  • 每次调度器执行Job时,它在调用execute方法前会创建一个新的Job实例
  • 当Job调用完成后,关联的Job对象会被释放,释放的实例会被垃圾回收机制回收

JobDetail的重要属性:

  1. name:任务名称
  2. group:任务组
  3. jobClass:任务对象
  4. jobDataMap: 可传输数据的集合

JobDetail的常用方法:

  1. jobDetail.getKey():获取任务类的基本信息,如:name(任务名),group(任务组),class(任务类)
  2. jobDetail.getJobDataMap():获取JobDataMap
  3. jobDetail.isDurable():Job没有触发器指向它的时候是否应该继续存储
  4. jobDetail.requestsRecovery():指示调度器在遇到“恢复”或“故障转移”情况时是否应重新执行作业
  5. jobDetail.withIdentity():设置任务名称和任务组,如果不指定使用默认任务名和任务组
  6. jobDetail.newJob():指定任务类,class类型
  7. jobDetail.usingJobData():给JobDataMap对象赋值
  8. ……

例1:演示在调度器每次调用Job时都会创建新的job对象

① 在Job中新建构造方法

public class HelloJob implements Job {
    
    public HelloJob() {
        System.out.println("HelloJob被创建");
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        //打印当前日期和数据
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateformat = simpleDateFormat.format(date);

        //执行任务
        System.out.println(dateformat+"--数据库备份!!");
    }
}

调用省略,直接测试:

HelloJob被创建
2022-10-12 17:33:38--数据库备份!!
HelloJob被创建
2022-10-12 17:33:45--数据库备份!!
HelloJob被创建
2022-10-12 17:33:52--数据库备份!!

例2:测试JobDetail方法

//1,调度器(Scheduler),从工厂中获取调度实例
Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();

//2,任务实例(JobDetail)
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//加载任务类
        .withIdentity("job1", "group1")//参数1:任务的名称 参数2:任务组的名称
        .build();
//获取任务名
System.out.println("任务名:"+jobDetail.getKey().getName());
//获取任务组
System.out.println("任务组:"+jobDetail.getKey().getGroup());
//获取任务类(class类型)
System.out.println("任务类:"+jobDetail.getKey().getClass());
//获取JobDataMap
System.out.println("任务存储数据map:"+jobDetail.getJobDataMap());

……省略

测试:

任务名:job1
任务组:group1
任务类:class org.quartz.JobKey
任务存储数据map:org.quartz.JobDataMap@0

4.2 JobExecutionContext说明

JobExecutionContext的作用:

  • 当Scheduler调用一个job,就会将jobExecutionContext对象传递给job的execute()方法的参数
  • Job能够通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据

JobExecutionContext的方法:

  • Scheduler getScheduler():获取当前调度器对象
  • Trigger getTrigger():获取当前触发器对象
  • JobDetail getJobDetail():获取任务实例对象
  • Date getFireTime():当前任务的执行时间
  • Date getNextFireTime():下一次任务的执行时间
  • void put(Object var1, Object var2):使用给定的键将指定的值放入上下文的数据映射中
  • Calendar getCalendar():获取触发的Calendar对象
  • Object get(Object var1):从上下文的数据映射中获取具有给定键的值
  • TriggerKey getRecoveringTriggerKey():返回最初计划的作业和现在正在恢复的作业
  • JobDataMap getMergedJobDataMap():获取JobDataMap数据集合
  • Job getJobInstance():获取为此执行创建的Job实例
  • long getJobRunTime():job运行的时间
  • ………………

例:

① job类

public class ExecutionJob implements Job {


    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {


        //获取任务实例
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        System.out.println("任务类名:"+jobDetail.getJobClass().getSimpleName());//类名
        System.out.println("任务组名:"+jobDetail.getKey().getGroup());//组名
        System.out.println("任务名称:"+jobDetail.getKey().getName());//任务名


        //获取触发器
        Trigger trigger = jobExecutionContext.getTrigger();


        //获取调度器
        Scheduler scheduler = jobExecutionContext.getScheduler();


        //获取时间
        System.out.println("当前任执行时间:"+jobExecutionContext.getFireTime());
        System.out.println("下一次任务执行时间:"+jobExecutionContext.getNextFireTime());
        System.out.println("任务运行时间:"+jobExecutionContext.getJobRunTime());


        //直接操作上下文数据映射的值
        jobExecutionContext.put("qt","晴天");
        System.out.println(jobExecutionContext.get("qt"));


        //获取JobDataMap
        JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
        System.out.println(mergedJobDataMap.get("kxj"));
    }
}

② 执行

//1,调度器(Scheduler),从工厂中获取调度实例
Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();

//jobDataMap
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("kxj","空想家");

//2,任务实例(JobDetail)
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class)//加载任务类
        .withIdentity("job1", "group1")//参数1:任务的名称 参数2:任务组的名称
        .usingJobData(jobDataMap)
        .build();

//3,触发器(Trigger)
SimpleTrigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("trigger1", "group1")//参数1:触发器名称 参数2:触发器组名称
        .startNow()//启动后立即执行触发器
        .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))//每2秒执行重复执行一次
        .build();


//Scheduler调度器关联任务实例和触发器,保证触发器定义的条件执行任务实例
defaultScheduler.scheduleJob(jobDetail,trigger);


//启动调度器
defaultScheduler.start();

输出:

任务类名:ExecutionJob
任务组名:group1
任务名称:job1
当前任执行时间:Thu Oct 13 12:00:17 CST 2022
下一次任务执行时间:Thu Oct 13 12:00:19 CST 2022
任务运行时间:-1
晴天
空想家

4.3 JobDataMap说明

JobDataMap介绍:

  • 在进行任务调度时,JobDataMap存储在JobExecutionContext中,非常方便获取
  • JobDataMap可以用来装载任何可序列化的数据对象,当job实例对象被执行时这些参数对象会被传递
  • JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法用来存储基本数据类型和引用数据类型

(1) 基本使用:

① 将job加入到scheduler之前,在构建JobDetail时,可以将数据放入JobDataMap,如下示例:

JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("kxj","空想家");

//2,任务实例(JobDetail)
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class)//加载任务类
        .withIdentity("job1", "group1")//参数1:任务的名称 参数2:任务组的名称
        .usingJobData(jobDataMap) //设置JobDataMap
        .build();

② 在job的执行过程中,可以从JobDataMap中取出数据,如下示例:

public class ExecutionJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        //获取JobDataMap
        JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
        System.out.println(mergedJobDataMap.get("kxj"));

    }
}
(2) Job实现类中添加setter方法对应JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化job实例对象时会自动地调用这些setter方法
private String kxj;

public void setKxj(String kxj) { //在初始化时被自动注入JobDataMap在的值,key为属性名
    this.kxj = kxj;
}

@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {


    //获取JobDataMap
    JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
    System.out.println(mergedJobDataMap.get("kxj")==kxj);

}

注:如果遇到同名的key,Trigger中的usingJobData会覆盖JobDetail中的usingJobData

4.4 Trigger触发器说明

Quartz有不同的触发器类型,其中用得最多的是SimpleTrigger和CronTrigger

Trigger的重要对象:

  • jobKey:表示job实例的标识,触发器被触发时,该指定的job实例会被执行
  • startTime:表示触发器第一次被触发时间,它的数据类型是java.util.Date
  • endTime:指定触发器终止被触发的时间,它的数据类型是java.util.Date

例:

① 任务实现类

public class TriggerJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        //当前时间
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd MM:mm:ss");
        System.out.println("任务当前时间"+simpleDateFormat.format(date));

        //获取Trigger
        Trigger trigger = jobExecutionContext.getTrigger();
        //通过Trigger获取jobKey
        JobKey jobKey = trigger.getJobKey();
        System.out.println(jobKey.getName());//获取job的名称
        System.out.println(jobKey.getGroup());//获取job的组名

        //任务开始时间
        System.out.println("任务开始时间"+simpleDateFormat.format(trigger.getStartTime()));

        //任务结束时间
        System.out.println("任务结束时间"+simpleDateFormat.format(trigger.getEndTime()));
    }
}

② 调度

Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();

JobDetail jobDetail = JobBuilder.newJob(TriggerJob.class)
        .withIdentity("job1", "group1")
        .build();

//任务开始时间
Date startdate = new Date();
startdate.setTime(startdate.getTime()+3000);//开始延迟3秒
//任务结束时间
Date enddate = new Date();
enddate.setTime(enddate.getTime()+5000);//结束延迟5秒

Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("trigger1", "group1")
        .startAt(startdate)//设置任务开始时间
        .endAt(enddate)//设置任务结束时间
        .build();

defaultScheduler.scheduleJob(jobDetail,trigger);

defaultScheduler.start();

测试:

任务当前时间2022-10-13 10:14:57
job1
group1
任务开始时间2022-10-13 10:14:56
任务结束时间2022-10-13 10:14:58

4.4.1 SimpleTrigger触发器说明

SimpleTrigger对于设置和使用是最为简单的一种QuartzTrigger,它是为需要在特定的日期/时间启动,且以一个可能的间隔时间重复执行n次的jon所设计的

SimpleTrigger的几个重要方法:

  1. startAt():
  2. endAt():
  3. SimpleScheduleBuilder.withRepeatCount():指定执行次数
  4. SimpleScheduleBuilder.repeat****Forever():指定间隔时间

例1:在一个当前时间推迟3秒执行任务,任务每5秒中执行一次,总共执行3次

① 任务类

public class SimpleTriggerJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateformat = simpleDateFormat.format(date);
        
        System.out.println(dateformat+"--数据库备份!!");
    }
}

② SimpleTrigger

Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();

JobDetail jobDetail = JobBuilder.newJob(SimpleTriggerJob.class)
        .withIdentity("job1", "group1")
        .build();

Date date = new Date();
date.setTime(date.getTime()+3000);//推迟三秒

SimpleTrigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("trigger1", "group1")
        .startAt(date)
        .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5).withRepeatCount(2))//5秒执行一次,总共3次(从0开始)
        .build();

defaultScheduler.scheduleJob(jobDetail,trigger);

defaultScheduler.start();

输出:

2022-10-14 15:27:02--数据库备份!!
2022-10-14 15:27:07--数据库备份!!
2022-10-14 15:27:12--数据库备份!!

注:withRepeatCount()的值执行次数从0次开始,2代表着3次;如果不指定次数每个时间间隔会重复执行

例2:指定任务结束时间

Date enddate = new Date();
enddate.setTime(enddate.getTime()+10000);//当前时间推迟10秒

SimpleTrigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("trigger1", "group1")
        .startNow()//启动会立即执行任务
        .endAt(enddate)//任务结束时间
        .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5).withRepeatCount(2))//5秒执行一次,总共3次(从0开始)
        .build();

注:

  • SimpleTrigger的属性有:开始时间,结束时间,重复次数,重复时间间隔
  • 重复次数的值可以为0,正整数,常量(SimpleTrigger.REPEAT_INDEFINTELY)
  • 重复的时间间隔属性值必须为0或长整型的正整数,以毫秒做为时间单位,当重复的时间间隔为0时,意味着于Trigger同时触发执行
  • 如果指定结束时间属性值,则结束时间优先于重复次数

4.4.2 CronTrigger触发器

 简介:CronTriggers是基于日历的任务触发器,如果需要像日历那样按照日程触发任务,而不是像SimpleTrigger那样每隔特定的时间间隔来触发,CrinTrigger是很好的选择

    使用CronTrigger,可以指定诸如“每个周五中午”,或者"每个工作日的9:30"或者“从每个同一、周三、周五的上午9: 00到上午10:00之间每隔五分钟"这样日程安排来触发。甚至,象SimpleTrigger一样,CronTrigger也有一个startTime以指定日程从什么时候开始,也有一个(可选的) endTime以指定何时日程不再继续

4.4.2.1 CronExpressions表达式

    Cron表达式被用来配置CronTrigger实例,Cron表达式是一个由7个子表达式组成的字符串,每一个子表达式都描述了一个单独的日程细节,这些子表达式用空格隔开,分别表示:

  • Seconds秒
  • Minutes分钟
  • Hours小时
  • Day-of-Month月中的天
  • Month月
  • Day-of-Week周中的天
  • Year 年(可选)

取值:

字段
是否必填
允许值
运行的特殊字符
Seconds(秒)
0-59
,  -  *  /
Minutes(分钟)
0-59
,  -  *  /
Hours(小时)
0-23
,  -  *  /
Day-of-Month(天)
1-31
,  -  *  /  ?  L  W  C
Month(月)
1-12或者JAN-DEC
,  -  *  /
Day-of-Week(星期几)
1-7或者SUN-SAT
,  -  *  / ?  L  C  #
Year(年)
1970-2099
,  -  *  /
    单个子表达式可以包含范围或者列表,例如:前面例子中的同中的天这个域(这里是"WED")可以被替换为"MON-FRI", "MON, WED, FRI"或者甚至"MON-WED,SAT".
    所有的域中的值都有特定的合法范围,这些值的合法范围相当明显,例如:秒和分域的合法值为0到59,小时的合法范围是0到23,Day-of-Month中值得合法凡范围是1到31,但是需要注意不同的月份中的天数不同。月份的合法值是1到12,或者用字符串JAN,FEB MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 及DEC来表示 Days-ofWeek可以用1到7来表示(1=星期日)或者用字符串SUN, MON, TUE, WED, THU, FRI 和SAT来表示

特殊字符含义:

特殊字符
含义
*
表示域中每一个可能的值。因此在"Month"域中*表示每个月,"Day-of-Week"域中表示每个星期
表示指定值,使用的场景为不需要关心当前设置这个字段的值。因为"月份中的日期"和"星期中的日期"是互斥的,因此应该通过一个问号(?)来表明不想设置的字段
-
表示一个区间,例如:在小时字段上设置10-12,则表示10,11,12点都会触发
,
表示指定多个值,例如:在周字段上设置"1,2,3",表示周一、周二、周三都会触发
/
表示值的增量,例如:分钟域值为"0/15"它表示"每隔15分钟,从0开始"
L
可以在day-of-month及day-of-week中使用,这个字符是"last"的简写,但是在两个域中的意义不同。例如,在day-of-month域中的"L"表示这个月的最后一天,即,一月的31日,非闻年的二月的28日。如果它用在day-of-week中,则表示"7"或者"SAT"。但是如果在day-of-week域中,这个字符跟在别的值后面,则表示"当月的最后的周XXX"。例如: "6L”或者"FRIL"都表示本月的最后一个周五。当使用"L"选项时,最重要的是不要指定列表或者值范围,否则会导致混乱
W
用来指定距离给定日最接近的周几(在day-of-week域中指定),例如:如果你为day-of-month域指定为"15W",则表示“距离月中15号最近的周几”
#
表示月中的第几个周几。例如: day-of-week域中的"6#3"或者"FRI#3"表示“月中第三个周五”
练习:
"0 0 10,15 * * ?"   每天上午10点,下午3点
"0 0/30 9-17 * * ?"  9点到17点每半,从0分开始每隔30分钟发送一次
"0 0 12 ? * WED"  表示每个星期三中午12点
"0 0 12 * * ?"  每天中午12点触发
"0 30 10 * * ?"  每天上午10:30触发
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发
"0 15 10 L * ?" 每月的最后一日的上午10:15触发

4.4.2.2 CronTrigger的使用

  • CronScheduleBuilder.cronSchedule:指定Cron表达式

例:

CronTrigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("trigger1", "group1")
        .startNow()
        .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * 14 10 ?"))//10月14号每5秒执行
        .build();

4.4.2.3 Cron表达式生成工具

地址:https://cron.qqe2.com/

4.5 Scheduler调度器说明

Quartz以模块方式架构,Scheduler就是相当于直接连接器,把Trigger和Job很好的连接起来

Quartz的三个核心概念:调度器(Scheduler),任务(Job),触发器(Trigger)

    Trigger对于job而言就好比一个驱动器,没有触发器来定时驱动作业,作业就无法运行;对于Job而言一个Job可以对应多个Trigger,但对于Trigger而言,一个Trigger只能对应一个Job,所以一个Trigger只能被指派一个Job,如果你需要一个更复杂的触发计划,可以创建多个Trigger并指派它们给同一个Job

Scheduler的创建方式:

(1) StdSchedulerFactory

Quartz默认的SchedulerFactory

  • 使用一组(java.util.Properties)来创建和初始化Quartz调度器
  • 配置参数一般存储在quartz.properties文件中
  • 调用getScheduler方法就能创建和初始化调度器对象
StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = stdSchedulerFactory.getScheduler();

用法一:输出调度器开始的时间

  • Date schedulerJob(JobDetail jobDetail, Trigger trigger):返回日期
Date date = defaultScheduler.scheduleJob(jobDetail, trigger);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("调度器开始的时间:"+simpleDateFormat.format(date));

用法二:启动任务调度

  • void start()
defaultScheduler.scheduleJob(jobDetail, trigger);

defaultScheduler.start();

用法三:任务调度挂起,即暂停操作

  • void standby()
defaultScheduler.scheduleJob(jobDetail, trigger);

defaultScheduler.standby();

用法四:关闭任务调度

  • shutdown(true):表示等待所以执行的job执行结束之后,再关闭Scheduler
  • shutdown(true):表示直接关闭Scheduler
//Schenuler执行2秒后自动挂起
Thread.sleep(2000L);
scheduler.standby();
//Schenuler执行5秒后自动开启
Thread.sleep(5000L);
scheduler.start();
//Schenuler执行8秒后自动关闭
Thread.sleep(8000L);
scheduler.shutdown(true)

5. Job的状态

job的状态:

  • 无状态(默认):job每一次调用都会重新创建,JobDataMap也会被重新加载
  • 有状态:job的多次调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap

默认job是无状态的,使用@PersistJobDataAfterExecution标注job类可以实现有状态

例1:使用无状态job尝试进行累加

public class CountJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        JobDataMap mergedJobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        Integer number = (Integer) mergedJobDataMap.get("number");

        number=number+1;
        System.out.println(number);
        jobExecutionContext.getJobDetail().getJobDataMap().put("number",number);
    }
}

结果:

1
1
1
1

例2:使用有状态job尝试进行累加

@PersistJobDataAfterExecution
public class CountJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        JobDataMap mergedJobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        Integer number = (Integer) mergedJobDataMap.get("number");
        number=number+1;
        System.out.println(number);
        jobExecutionContext.getJobDetail().getJobDataMap().put("number",number);
    }}

结果:

1
2
3
4

路漫漫其修远兮,吾将上下而求索