Quartz 是什么

  • 一、初始Quartz
  • 二、实战Quartz
  • 三、几个重要参数
  • 四、Qurartz监听器

参考链接
https://wjrsbu.smartapps.cn/zhihu/article?id=306591082&isShared=1&_swebfr=1&_swebFromHost=baiduboxapp

一、初始Quartz

  1. 概念
    quartz是一款开源且丰富特性的任务调度库,能够集成与任何java的应用,下到独立应用,大到电子商业系统。quartz就是基于java实现的任务调度框架,用于执行你想要执行的任何任务。
    什么是 任务调度 ?任务调度就是我们系统中创建了 N 个任务,每个任务都有指定的时间进行执行,而这种多任务的执行策略就是任务调度。
    quartz 的作用就是让任务调度变得更加丰富,高效,安全,而且是基于 Java 实现的,这样子开发者只需要调用几个接口坐下简单的配置,即可实现上述需求。
  2. 核心
  • 任务Job
    我们想要调度的任务都必须实现 org.quartz.job 接口,然后实现接口中定义的 execute( ) 方法即可。
  • 触发器Trigger
    Trigger 作为执行任务的调度器。我们如果想要凌晨1点执行备份数据的任务,那么 Trigger 就会设置凌晨1点执行该任务。其中 Trigger 又分为 SimpleTrigger 和 CronTrigger 两种。
  • 调度器Scheduler
    Scheduler 为任务的调度器,它会将任务 Job 及触发器 Trigger 整合起来,负责基于 Trigger 设定的时间来执行 Job。
  1. 体系结构

二、实战Quartz

  1. 导入相应的jar包
  2. 自定义任务
public class TestJob implements Job {public void execute(JobExecutionContext jobExecutionContext) {String data = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));System.out.println("START DATA BACKUP, current time :" + data);}
}
  1. 创建任务调度
package com.test.schedular;import java.util.Date;import org.quartz.Scheduler;
import org.quartz.impl.JobDetailImpl;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.triggers.SimpleTriggerImpl;import com.test.Job.TestJob;public class TestScheduler {public static void main(String[] args) throws Exception { // 获取任务调度的实例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); //// 定义任务调度实例, 并与TestJob绑定 // JobDetail job = //JobDetailImpl jobdetail = new JobDetailImpl();jobdetail.setJobClass(TestJob.class);jobdetail.setName("testJob");jobdetail.setGroup("testJobGroup"); // 定义触发器, 会马上执行一次, 接着5秒执行一次 //SimpleTriggerImpl trigger1 = new SimpleTriggerImpl();trigger1.setStartTime(new Date());trigger1.setGroup("testTriggerGroup");trigger1.setName("testJob"); // 使用触发器调度任务的执行trigger1.setRepeatInterval(5000l);trigger1.setRepeatCount(-1);trigger1.setMisfireInstruction(0);scheduler.scheduleJob(jobdetail, trigger1); // 开启任务scheduler.start();}或者public static void main(String[] args) throws Exception { // 获取任务调度的实例// 获取任务调度的实例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定义任务调度实例, 并与TestJob绑定JobDetail job = JobBuilder.newJob(TestJob.class).withIdentity("testJob", "testJobGroup").build();// 定义触发器, 会马上执行一次, 接着5秒执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();// 使用触发器调度任务的执行scheduler.scheduleJob(job, trigger);// 开启任务scheduler.start();}
}

/** OUTPUT:
START DATA BACKUP, current time :2020-11-17 21:48:30
START DATA BACKUP, current time :2020-11-17 21:48:35
START DATA BACKUP, current time :2020-11-17 21:48:40
START DATA BACKUP, current time :2020-11-17 21:48:45
**/

三、几个重要参数

  1. Job和JobDetail
  • Job
    Job是工作任务调度的接口,任务类需要实现该接口。该接口定义了excute方法,我们需要在里编写任务执行的业务逻辑,类似JDK提供的TimeTask类的run方法。每次调度器执行Job时,在调用execute方法之前都会创建一个新的Job实例,当调用完成后,关联的Job对象实例会被释放,释放的实例会被垃圾回收机制回收。
  • JobDetail
    JobDetail是为Job实例提供了许多设置属性,以及JobDetailMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例。
    其中有几个重要属性:
    JobDataMap jobDataMap = jobDetail.getJobDataMap();
    String name = jobDetail.getKey().getName();
    String group = jobDetail.getKey().getGroup();
    String jobName = jobDetail.getJobClass().getName();
    两者之间的关系
    JobDetail定义的是任务数据,而真正的执行逻辑是在Job中。这是因为任务是可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而采用JobDetail&Job方式,Scheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。
  1. JobExecutionContext
    当 Scheduler 调用一个 Job ,就会将 JobExecutionContext 传递给 Job 的 execute() 方法。这样子在Job 中就能通过 JobExecutionContext 对象来访问到 Quartz 运行时候的环境以及 Job 本身的明细数据。
public class TestJob implements Job {public void execute(JobExecutionContext jobExecutionContext) {String data = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));System.out.println("START DATA BACKUP, current time :" + data);}
}

  1. JobDataMap
    顾名思义 JobDataMap 是一个 Map ,它实现了 JDK中的 Map 接口,可以用来存取基本数据类型,也可以用来转载任何可序列化的数据对象,当 Job 实例对象被执行时这些参数对象会传递给它。示例如下:
  • 任务调度类
JobDetail jobDetail = JobBuilder.newJob(TestJob.class).usingJobData("testJobDetail", "jobDetail数据存放").withIdentity("testJob", "testJobGroup").build();
Trigger trigger = TriggerBuilder.newTrigger().usingJobData("testTrigger", "trigger数据存放").withIdentity("testTrigger", "testTriggerGroup").startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();
  • Job任务类
public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) {System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("testJobDetail"));System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("testTrigger"));}
}

/** OUTPUT:
jobDetail数据存放
trigger数据存放
**/
以上我们是通过 getJobDataMap( ) 方法来获取 JobDataMap 中的值,我们还可以使用另外一种方式来获取:

  • Job 任务类:
public class TestJob implements Job {private String testJobDetail;public void setTestJobDetail(String testJobDetail) {this.testJobDetail = testJobDetail;}@Overridepublic void execute(JobExecutionContext jobExecutionContext) {System.out.println(testJobDetail);}
}

/** OUTPUT:
jobDetail数据存放
**/

以上方式便是: 只要我们在Job实现类中添加对应key的setter方法,那么Quartz框架默认的JobFactory实现类在初始化 Job 实例对象时回自动地调用这些 setter 方法


注: 如果遇到同名的 key,比如我们在JobDetail 中存放值的 key 与在 Trigger 中存放值的 key 相同,那么最终 Trigger 的值会覆盖掉 JobDetail 中的值,示例如下:

  • 任务调度类:两者中都存放了 key 为 testInfo 的值
 public static void main(String[] args) throws Exception { // 获取任务调度的实例// 获取任务调度的实例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定义任务调度实例, 并与TestJob绑定JobDetail job = JobBuilder.newJob(TestJob.class).usingJobData("testJobDetail", "jobDetail数据存放").withIdentity("testJob", "testJobGroup").build();// 定义触发器, 会马上执行一次, 接着5秒执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").startNow().usingJobData("testINfo", "trigger数据存放").withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();// 使用触发器调度任务的执行scheduler.scheduleJob(job, trigger);// 开启任务scheduler.start();}
  • Job 任务类:会输出 Trigger 中存放的值
public class TestJob implements Job {private String testJobDetail;public void setTestJobDetail(String testJobDetail) {this.testJobDetail = testJobDetail;}private String testINfo;public String getTestINfo() {return testINfo;}public void setTestINfo(String testINfo) {this.testINfo = testINfo;}public String getTestJobDetail() {return testJobDetail;}@Overridepublic void execute(JobExecutionContext jobExecutionContext) {System.out.println("testINfo--->" + testINfo);System.out.println("testJobDetail--->" + testJobDetail);}
}
  1. Job的状态
    如果我们有个需求是统计每个任务的执行次数,那么你会怎么做?
    也许你会想到使用上面说到的 JobDataMap,那就让我们尝试下:
  • 任务调度类
// 我们在 JobDataMap 中定义了一个值为 0 的初始值
JobDetail jobDetail = JobBuilder.newJob(TestJob.class).usingJobData("executeCount", 0).withIdentity("testJob", "testJobGroup").build();
  • Job任务类
@Slf4j
public class TestJob implements Job {private Integer executeCount;public void setExecuteCount(Integer executeCount) {this.executeCount = executeCount;}@Overridepublic void execute(JobExecutionContext jobExecutionContext) {String data = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));log.info("execute count: {}, current time: {}",++executeCount, data);//将累加的 count 存入JobDataMap中jobExecutionContext.getJobDetail().getJobDataMap().put("executeCount", executeCount);}
}

/** OUTPUT:
execute count: 1, current time: 2020-11-17 22:38:48
execute count: 1, current time: 2020-11-17 22:38:52
execute count: 1, current time: 2020-11-17 22:38:57
**/

按照上面的想法我们写出了这部分代码,但貌似打脸了,结果并没有按照我们预计的发展,是逻辑不对吗,貌似写的也没什么问题。这时你会不会回忆到上面我讲过的一句话:"在调用 execute 方法之前都会创建一个新的 Job 实例",这就牵引出了 Job 状态的概念:

  • 无状态的job
    每次调用时都会创建一个新的jobDataMap
  • 有状态的Job
    多次Job调用可以持有一些状态信息,这些状态信息存储在jobDataMap中
    那么问题来了,如果让 Job 变成有状态?这个时候我们可以借助一个注解:@PersistJobDataAfterExecution,加上这个注解后,我们再来试下:
  • Job任务类
@Slf4j
@PersistJobDataAfterExecution
public class TestJob implements Job {private Integer executeCount;public void setExecuteCount(Integer executeCount) {this.executeCount = executeCount;}@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {String data = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));log.info("execute count: {}, current time: {}",++executeCount, data);//将累加的 count 存入JobDataMap中jobExecutionContext.getJobDetail().getJobDataMap().put("executeCount", executeCount);}
}

/** OUTPUT:
execute count: 1, current time: 2020-11-17 22:28:48
execute count: 2, current time: 2020-11-17 22:28:52
execute count: 3, current time: 2020-11-17 22:28:57
**/

可以看到加了 @PersistJobDataAfterExecution ,我们已经成功达到了我们的目的。

  1. Trigger
    经过以上示例,我们已经大概知道了 Quartz 的组成,我们定义了任务之后,需要用触发器 Trigger 去指定 Job 的执行时间,执行间隔,运行次数等,那么 Job 与 Trigger 的结合,我们中间还需要 Scheduler 去调度,三者关系大致如下:
    其中 Trigger 又有几种实现类如下:

大致有四个实现类,但是我们平时用的最多的还是 CronTriggerImpl 和 SimpleTriggerImpl
我们如果想要定义任务何时执行,何时结束,我们可以这样做:

  • 任务调度类
Date startTime = new Date();
startTime.setTime(startTime.getTime() + 5000);
Date endTime = new Date();
endTime.setTime(startTime.getTime() + 10000);
Trigger trigger = TriggerBuilder.newTrigger().usingJobData("testInfo", "trigger数据存放").withIdentity("testTrigger", "testTriggerGroup").startNow().startAt(startTime).endAt(endTime).withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();
  • Job任务类
@Slf4j
@PersistJobDataAfterExecution
public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {Trigger trigger = jobExecutionContext.getTrigger();log.info("start time : {}, end time: {}",trigger.getStartTime(), trigger.getEndTime());}
}

/** OUTPUT:
start time : Thu Nov 17 22:42:51 CST 2020, end time: Thu Nov 17 22:43:01 CST 2020
start time : Thu Nov 17 22:42:51 CST 2020, end time: Thu Nov 17 22:43:01 CST 2020
**/

通过控制台可以看到,任务执行了两次便已经停止了,因为已经超过了停止时间 Thu Nov 17 22:43:01 CST 2020

  • SimpleTrigger
    我们上面看到示例,用到的都是 SimpleTrigger ,SimpleTrigger 对于设置和使用是最为简单的一种 QuartzTrigger它是为那种需要在特定的日期/时间启动,且以一个可能的间隔时间重复执行 n 次的 Job任务 所设计的
    比如我想要在一个指定的时间段内执行一次任务,我们只需要这样写:
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").startAt(startTime) //自定义执行时间.build();

再者我想在指定的时间间隔内多次执行该任务,我们可以这样写:

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).withRepeatCount(2)) // 每5秒执行一次,连续执行3次后停止,从 0 开始计数.build();

我们来总结一下上面的示例:

  • SimpleTrigger具备的属性有:开始时间、结束时间、重复次数和重复的时间间隔
  • 重复次数 的值可以为 0、正整数、或常量 SimpleTrigger.REPEAT_INDEFINITELY
  • 重复的时间间隔属性值必须大于 0 或长整型的正整数,以 毫秒 作为时间单位,当重复的时间间隔为 0 时,意味着与 Trigger 同时触发执行
  • 结束时间和重复次数同时存在时,以结束时间优先
  • CronTrigger
    跟 SimpleTrigger 执行间隔时间触发的相比,CronTrigger 更加灵活,它是基于日历的作业调度器。使用 CronTrigger 我们可以执行某个时间点执行,例如 “每天的凌晨1点执行”、“每个工作日的 12 点执行”,也可以像 SimpleTrigger 那样执行一个开始时间和结束时间运行任务
    学习 CronTrigger 之前我们得先学习 Cron 表达式
  • Cron表达式

Seconds:秒
Minutes:分钟
Hours:小时
Day-of-Month:月中的哪几天
Month:月
Day-of-Week:周中的哪几天
Year:年

字段 是否必填 允许值 可用特殊字符
0-59 , - * /
0-59 , - * /
小时 0-23 , - * /
月中的哪几天 1-31 , - * / ? L W C
1-12 或 JAN-DEC , - * /
周中的哪几天 1-7 或 SUN-SAT , - * / ? L C #
不填写 或 1970-2099 , - * /
特殊符号 含义
* 可用在所有字段中,表示对应时间域的每一个时刻,例如,***** 在分钟字段时,表示“每分钟”
? 该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符
- 表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12
, 表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五
/ x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y
L 该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值 X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五
W 该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围
# 该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发

Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。

  • 实战演习

“0 0 10,14,16 * * ?” 每天上午10点,下午2点,4点
“0 0/30 9-17 * * ?” 朝九晚五工作时间内每半小时,从0分开始每隔30分钟发送一次
“0 0 12 ? * WED” 表示每个星期三中午12点
“0 0 12 * * ?” 每天中午12点触发
“0 15 10 ? * *” 每天上午10:15触发
“0 15 10 * * ?” 每天上午10:15触发
“0 15 10 * * ? *” 每天上午10:15触发
“0 15 10 * * ? 2005” 2005年的每天上午10:15触发
“0 * 14 * * ?” 在每天下午2点到下午2:59期间的每1分钟触发
“0 0/55 14 * * ?” 在每天下午2点到下午2:55期间,从0开始到55分钟触发
“0 0-5 14 * * ?” 在每天下午2点到下午2:05期间的每1分钟触发
“0 10,44 14 ? 3 WED” 每年三月的星期三的下午2:10和2:44触发
“0 15 10 ? * MON-FRI” 周一至周五的上午10:15触发
“0 15 10 15 * ?” 每月15日上午10:15触发
“0 15 10 L * ?” 每月最后一日的上午10:15触发
“0 15 10 ? * 6L” 每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6#3” 每月的第三个星期五上午10:15触发

  • 使用示例
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * 6 4 ?")).build();
  1. Scheduler
    Quartz 是以模块的方式构建的,Job 和 Trigger 之间的结合需要靠 Scheduler。
  • 创建
    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    创建是通过 Quartz 默认的 SchedulerFactory,我们可以使用自定义参数(Properties)来创建和初始化 Quartz 调度器,配置参数一般存储在 quartz.properties 中。
    我们上面是通过 scheduleJob() 方法来结合 Job和 Trigger,这个方法有个时间类型的返回值,我们可以获取到调度器开始的时间:
    Date date = scheduler.scheduleJob(jobDetail, trigger);
    关联完任务和触发器,我们就可以启动任务调度了:
    scheduler.start();
    将任务调度挂起(暂停):
    scheduler.standby();
    将任务关闭:
    shutdown(true);//表示等待所有正在执行的job执行完毕之后,再关闭Scheduler
    shutdown(false);//表示直接关闭Scheduler

我们再来了解下 quartz.properties 文件,先看一个示例:
也可以编写程序代码操作quartz.properties文件的内容:

public class QuartzProperties {public static void main(String[] args) {// 创建工厂实例StdSchedulerFactory factory = new StdSchedulerFactory();// 创建配置工厂的属性对象Properties props = new Properties();props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, "org.quartz.simpl.SimpleThreadPool"); // 线程池定义props.put("org.quartz.threadPool.threadCount", "5"); // 默认Scheduler的线程数try {// 使用定义的属性初始化工厂factory.initialize(props);Scheduler scheduler = factory.getScheduler();scheduler.start();} catch (SchedulerException e) {e.printStackTrace();}}
}

通过Properties设置工厂属性的缺点在用硬编码,假如需要修改例子中线程数量,将不得不修改代码,然后重新编译,所以不推荐使用。

四、Qurartz监听器

在 Quartz 实战中我们了解到三个核心模块分别是 Job、Trigger、Scheduler,既然 Quartz中存在监听器,相应的,这三者也分别有对应的监听器。监听器的作用便是用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知

  1. JobListener
public interface JobListener
{public abstract String getName();public abstract void jobToBeExecuted(JobExecutionContext jobexecutioncontext);public abstract void jobExecutionVetoed(JobExecutionContext jobexecutioncontext);public abstract void jobWasExecuted(JobExecutionContext jobexecutioncontext, JobExecutionException jobexecutionexception);
}

getName():用于获取改JobListener 的名称
jobToBeExecuted():Scheduler 在 JobDetail 将要被执行时调用这个方法
``jobExecutionVetoed()`:Scheduler 在 JobDetail 即将被执行,但又被 TriggerListener 否决时会调用该方法
jobWasExecuted():Scheduler 在 JobDetail 被执行之后调用这个方法

  1. 示例
  • Job任务类
package com.test.Job;import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.PersistJobDataAfterExecution;@PersistJobDataAfterExecution
public class TestJob implements Job {private String testJobDetail;public void setTestJobDetail(String testJobDetail) {this.testJobDetail = testJobDetail;}private String testINfo;public String getTestINfo() {return testINfo;}public void setTestINfo(String testINfo) {this.testINfo = testINfo;}public String getTestJobDetail() {return testJobDetail;}Integer count;public Integer getCount() {return count;}public void setCount(Integer count) {this.count = count;}@Overridepublic void execute(JobExecutionContext jobExecutionContext) {/** System.out.println("testINfo--->" + testINfo);* System.out.println("testJobDetail--->" + testJobDetail);* System.out.println("count--->" + (++count));*/// 将累加的 count 存入JobDataMap中jobExecutionContext.getJobDetail().getJobDataMap().put("count", count);}
}
  • JobListener
package com.test.Listener;import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;public class myJobListener implements JobListener {@Overridepublic String getName() {// TODO Auto-generated method stubString name = getClass().getSimpleName();System.out.println("监听器名称是:" + name);return name;}@Overridepublic void jobExecutionVetoed(JobExecutionContext jobexecutioncontext) {// TODO Auto-generated method stubString jobName = jobexecutioncontext.getJobDetail().getKey().getName();System.out.println("Job的名称是:" + jobName + "\tScheduler在JobDetail将要被执行时调用这个方法");}@Overridepublic void jobToBeExecuted(JobExecutionContext jobexecutioncontext) {// TODO Auto-generated method stubString jobName = jobexecutioncontext.getJobDetail().getKey().getName();System.out.println("Job的名称是:" + jobName + "\tScheduler在JobDetail即将被执行,但又被TriggerListerner否决时会调用该方法");}@Overridepublic void jobWasExecuted(JobExecutionContext jobexecutioncontext, JobExecutionException jobexecutionexception) {// TODO Auto-generated method stubString jobName = jobexecutioncontext.getJobDetail().getKey().getName();System.out.println("Job的名称是:" + jobName + "\tScheduler在JobDetail被执行之后调用这个方法");}}
  • 任务调度类
package com.test.schedular;import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.EverythingMatcher;import com.test.Job.TestJob;
import com.test.Listener.myJobListener;public class TestScheduler {public static void main(String[] args) throws Exception { // 获取任务调度的实例// int count = 0;// 获取任务调度的实例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定义任务调度实例, 并与TestJob绑定JobDetail job = JobBuilder.newJob(TestJob.class).usingJobData("testJobDetail", "jobDetail数据存放").usingJobData("count", 0).withIdentity("testJob", "testJobGroup").build();// 定义触发器, 会马上执行一次, 接着5秒执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").startNow().usingJobData("testINfo", "trigger数据存放").withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();/** addJobListener(JobListener joblistener, Matcher matcher); Matcher* 实现类EverythingMatcher public static EverythingMatcher allJobs() {* return new EverythingMatcher(); } public static EverythingMatcher* allTriggers() { return new EverythingMatcher(); }*/scheduler.getListenerManager().addJobListener(new myJobListener(), EverythingMatcher.allJobs());// 使用触发器调度任务的执行scheduler.scheduleJob(job, trigger);// 开启任务scheduler.start();}
}

/** OUTPUT:
testTrigger 被触发
testTrigger 没有被触发
TestJob 执行啦
testTrigger 完成之后触发
**/

  1. TriggerListener
    任务调度中,与触发器 Trigger 相关的事件包括: 触发器触发、触发器未正常触发、触发器完成等:
public interface TriggerListener
{public abstract String getName();public abstract void triggerFired(Trigger trigger, JobExecutionContext jobexecutioncontext);public abstract boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobexecutioncontext);public abstract void triggerMisfired(Trigger trigger);public abstract void triggerComplete(Trigger trigger, JobExecutionContext jobexecutioncontext, Trigger.CompletedExecutionInstruction completedexecutioninstruction);
}
  • getName():用于获取触发器的名称
  • triggerFired():当与监听器相关联的Trigger被触发,Job上的**execute()**方法将被执行时,Scheduler就调用该方法
  • vetoJobExecution():在 Trigger 触发后,Job 将要被执行时由 Scheduler 调用这个方法。TriggerListener 给了一个选择去否决 Job 的执行。假如这个方法返回 true,这个 Job 将不会为此次 Trigger 触发而得到执行
  • triggerMisfired():Scheduler 调用这个方法是在 Trigger 错过触发时。你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的 Trigger 时,长逻辑会导致骨牌效应,所以应当保持这方法尽量的小
  • triggerComplete():Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个方法。

示例

  • job任务类同上
  • TriggerListener
package com.test.Listener;import org.quartz.JobExecutionContext;
import org.quartz.Trigger;
import org.quartz.TriggerListener;public class myTriggerListener implements TriggerListener {private String name;public myTriggerListener(String name) {this.name = name;}@Overridepublic String getName() {return name;}@Overridepublic void triggerFired(Trigger trigger, JobExecutionContext context) {String triggerName = trigger.getKey().getName();System.out.println(triggerName + " 被触发");}@Overridepublic boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {String triggerName = trigger.getKey().getName();System.out.println(triggerName + " 没有被触发");return false; // true:表示不会执行Job的方法}@Overridepublic void triggerMisfired(Trigger trigger) {String triggerName = trigger.getKey().getName();System.out.println(triggerName + " 错过触发");}@Overridepublic void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext,Trigger.CompletedExecutionInstruction completedExecutionInstruction) {String triggerName = trigger.getKey().getName();System.out.println(triggerName + " 完成之后触发");}}
  • 任务调度类
package com.test.schedular;import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.EverythingMatcher;import com.test.Job.TestJob;
import com.test.Listener.myTriggerListener;public class TestScheduler {public static void main(String[] args) throws Exception { // 获取任务调度的实例// int count = 0;// 获取任务调度的实例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定义任务调度实例, 并与TestJob绑定JobDetail job = JobBuilder.newJob(TestJob.class).usingJobData("testJobDetail", "jobDetail数据存放").usingJobData("count", 0).withIdentity("testJob", "testJobGroup").build();// 定义触发器, 会马上执行一次, 接着5秒执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").startNow().usingJobData("testINfo", "trigger数据存放").withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();/** addJobListener(JobListener joblistener, Matcher matcher); Matcher* 实现类EverythingMatcher public static EverythingMatcher allJobs() {* return new EverythingMatcher(); } public static EverythingMatcher* allTriggers() { return new EverythingMatcher(); }*/// scheduler.getListenerManager().addJobListener(new myJobListener(),// EverythingMatcher.allJobs());/** new myTriggerListener("aaa") 并没有生效*/scheduler.getListenerManager().addTriggerListener(new myTriggerListener("aaa"),EverythingMatcher.allTriggers());// 使用触发器调度任务的执行scheduler.scheduleJob(job, trigger);// 开启任务scheduler.start();}
}
  1. SchedulerListener
    SchedulerListener会在Scheduler的生命周期中关键事件发生时被调用。与Scheduler有关的事件包括:增加一个job/trigger,删除一个job/trigger,scheduler发生严重错误,关闭scheduler等。
/*jadclipse*/// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.package org.quartz;// Referenced classes of package org.quartz:
//            Trigger, TriggerKey, JobDetail, JobKey,
//            SchedulerExceptionpublic interface SchedulerListener
{public abstract void jobScheduled(Trigger trigger);public abstract void jobUnscheduled(TriggerKey triggerkey);public abstract void triggerFinalized(Trigger trigger);public abstract void triggerPaused(TriggerKey triggerkey);public abstract void triggersPaused(String s);public abstract void triggerResumed(TriggerKey triggerkey);public abstract void triggersResumed(String s);public abstract void jobAdded(JobDetail jobdetail);public abstract void jobDeleted(JobKey jobkey);public abstract void jobPaused(JobKey jobkey);public abstract void jobsPaused(String s);public abstract void jobResumed(JobKey jobkey);public abstract void jobsResumed(String s);public abstract void schedulerError(String s, SchedulerException schedulerexception);public abstract void schedulerInStandbyMode();public abstract void schedulerStarted();public abstract void schedulerStarting();public abstract void schedulerShutdown();public abstract void schedulerShuttingdown();public abstract void schedulingDataCleared();
}/*DECOMPILATION REPORTDecompiled from: E:\myeclipseworkspace\Myeclipse 2016\testQuartz\WebRoot\WEB-INF\lib\quartz-2.3.2.jarTotal time: 371 msJad reported messages/errors:
The class file version is 51.0 (only 45.3, 46.0 and 47.0 are supported)Exit status: 0Caught exceptions:
*/
  • jobScheduled():用于部署JobDetail时调用
  • jobUnscheduled():用于卸载JobDetail时调用
  • triggerFinalized():当一个 Trigger 来到了再也不会触发的状态时调用这个方法。除非这个 Job 已设置成了持久性,否则它就会从 Scheduler 中移除。
  • triggersPaused():Scheduler 调用这个方法是发生在一个 Trigger 或 Trigger 组被暂停时。假如是 >+ Trigger 组的话,triggerName 参数将为 null。
  • triggersResumed():Scheduler 调用这个方法是发生成一个 Trigger 或 Trigger 组从暂停中恢复时。假如是 Trigger 组的话,假如是 Trigger 组的话,triggerName 参数将为 null。参数将为 null。
  • jobsPaused():当一个或一组 JobDetail 暂停时调用这个方法。
  • jobsResumed():当一个或一组 Job 从暂停上恢复时调用这个方法。假如是一个 Job 组,jobName 参数将为 null。
  • schedulerError():在 Scheduler 的正常运行期间产生一个严重错误时调用这个方法。
  • schedulerStarted():当Scheduler 开启时,调用该方法
  • schedulerInStandbyMode(): 当Scheduler处于StandBy模式时,调用该方法
  • schedulerShutdown()):当Scheduler停止时,调用该方法
  • schedulingDataCleared():当Scheduler中的数据被清除时,调用该方法。

示例:

  • job同上
  • SchedulerListener
package com.test.Listener;import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
import org.quartz.SchedulerListener;
import org.quartz.Trigger;
import org.quartz.TriggerKey;public class MySchedulerListener implements SchedulerListener {@Overridepublic void jobScheduled(Trigger trigger) {String jobName = trigger.getJobKey().getName();System.out.println(jobName + " 完成部署");}@Overridepublic void jobUnscheduled(TriggerKey triggerKey) {System.out.println(triggerKey + " 完成卸载");}@Overridepublic void triggerFinalized(Trigger trigger) {System.out.println("触发器被移除 " + trigger.getJobKey().getName());}@Overridepublic void triggerPaused(TriggerKey triggerKey) {System.out.println(triggerKey + " 正在被暂停");}@Overridepublic void triggersPaused(String triggerGroup) {System.out.println("触发器组 " + triggerGroup + " 正在被暂停");}@Overridepublic void triggerResumed(TriggerKey triggerKey) {System.out.println(triggerKey + " 正在从暂停中恢复");}@Overridepublic void triggersResumed(String triggerGroup) {System.out.println("触发器组 " + triggerGroup + " 正在从暂停中恢复");}@Overridepublic void jobAdded(JobDetail jobDetail) {System.out.println(jobDetail.getKey() + " 添加工作任务");}@Overridepublic void jobDeleted(JobKey jobKey) {System.out.println(jobKey + " 删除工作任务");}@Overridepublic void jobPaused(JobKey jobKey) {System.out.println(jobKey + " 工作任务正在被暂停");}@Overridepublic void jobsPaused(String jobGroup) {System.out.println("工作任务组 " + jobGroup + " 正在被暂停");}@Overridepublic void jobResumed(JobKey jobKey) {System.out.println(jobKey + " 正在从暂停中恢复");}@Overridepublic void jobsResumed(String jobGroup) {System.out.println("工作任务组 " + jobGroup + " 正在从暂停中恢复");}@Overridepublic void schedulerError(String msg, SchedulerException cause) {System.out.println("产生严重错误时调用:   " + msg + "  " + cause.getUnderlyingException());}@Overridepublic void schedulerInStandbyMode() {System.out.println("调度器在挂起模式下调用");}@Overridepublic void schedulerStarted() {System.out.println("调度器 开启时调用");}@Overridepublic void schedulerStarting() {System.out.println("调度器 正在开启时调用");}@Overridepublic void schedulerShutdown() {System.out.println("调度器 已经被关闭 时调用");}@Overridepublic void schedulerShuttingdown() {System.out.println("调度器 正在被关闭 时调用");}@Overridepublic void schedulingDataCleared() {System.out.println("调度器的数据被清除时调用");}
}
  • 任务调度器
package com.test.schedular;import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;import com.test.Job.TestJob;
import com.test.Listener.MySchedulerListener;public class TestScheduler {public static void main(String[] args) throws Exception { // 获取任务调度的实例// int count = 0;// 获取任务调度的实例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定义任务调度实例, 并与TestJob绑定JobDetail job = JobBuilder.newJob(TestJob.class).usingJobData("testJobDetail", "jobDetail数据存放").usingJobData("count", 0).withIdentity("testJob", "testJobGroup").build();// 定义触发器, 会马上执行一次, 接着5秒执行一次Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").startNow().usingJobData("testINfo", "trigger数据存放").withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();/** addJobListener(JobListener joblistener, Matcher matcher); Matcher* 实现类EverythingMatcher public static EverythingMatcher allJobs() {* return new EverythingMatcher(); } public static EverythingMatcher* allTriggers() { return new EverythingMatcher(); }*/// scheduler.getListenerManager().addJobListener(new myJobListener(),// EverythingMatcher.allJobs());/** new myTriggerListener("aaa") 并没有生效*//** scheduler.getListenerManager().addTriggerListener(new* myTriggerListener("aaa"), EverythingMatcher.allTriggers());*/scheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());// 使用触发器调度任务的执行scheduler.scheduleJob(job, trigger);// 开启任务scheduler.start();}
}

/** OUTPUT:
testJobGroup.testJob 添加工作任务
testJob 完成部署
调度器 正在开启时调用
调度器 开启时调用
TestJob 执行啦
触发器被移除 testJob
testJobGroup.testJob 删除工作任务
**/

Quartz 是什么相关推荐

  1. SpringBoot中实现quartz定时任务

    Quartz整合到SpringBoot(持久化到数据库) 背景 最近完成了一个小的后台管理系统的权限部分,想着要扩充点东西,并且刚好就完成了一个自动疫情填报系统,但是使用的定时任务是静态的,非常不利于 ...

  2. Java基于Quartz的定时任务调度服务(一)

    Quartz的基本用法 一 Quartz的简单介绍 Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现,一个优秀的开源调度框架,其特点是:强大的 ...

  3. springboot整合Quartz实现动态配置定时任务

    版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/liuchuanhong1/article/details/60873295 前言 在我们日常的开发中,很多 ...

  4. Quartz 2D Programming Guide笔记

    ###Graphics Contexts图形上下文### 图形上下文(graphics context)是绘制目标,可以理解为画布,包含着绘图时的参数和设备信息.类型为CGContextRef.获取g ...

  5. 【Quartz】实现接口封装化(二)

    原文:[Quartz]实现接口封装化(二)   前言   通过昨天的努力终于算是了解Quartz这个定时器的简单使用,为了更深一步的了解和基于以后希望在项目中能使用他.所有我对他做了一下简单的封装操作 ...

  6. quartz在集群环境下的最终解决方案

    在集群环境下,大家会碰到一直困扰的问题,即多个 APP 下如何用 quartz 协调处理自动化 JOB . 大家想象一下,现在有 A , B , C3 台机器同时作为集群服务器对外统一提供 SERVI ...

  7. 将Quartz.NET集成到 Castle中

    Castle是针对.NET平台的一个开源项目,从数据访问框架ORM到IOC容器,再到WEB层的MVC框架.AOP,基本包括了整个开发过程中的所有东西,为我们快速的构建企业级的应用程序提供了很好的服务. ...

  8. 初识Quartz(三)

    为什么80%的码农都做不了架构师?>>>    简单作业: package quartz_project.example3;import java.util.Date;import ...

  9. java timer cron_Java之旅--定时任务(Timer、Quartz、Spring、LinuxCron)

    在Java中,实现定时任务有多种方式.本文介绍4种.Timer和TimerTask.Spring.QuartZ.Linux Cron. 以上4种实现定时任务的方式.Timer是最简单的.不须要不论什么 ...

  10. Quartz动态添加、修改和删除定时任务

    2019独角兽企业重金招聘Python工程师标准>>> Quartz动态添加.修改和删除定时任务 转载于:https://my.oschina.net/haokevin/blog/1 ...

最新文章

  1. hadoop生态搭建(3节点)-06.hbase配置
  2. python 函数(二)
  3. Ubuntu解压缩zip,tar,tar.gz,tar.bz2
  4. python基础教程: os.stat() 和 stat模块详解
  5. 从Commons CLI迁移到picocli
  6. inventor扳手制作视频_弱电工程视频监控系统施工方案,可作施工组织设计
  7. python删除数据库_用Python删除Cosmos数据库文档
  8. 关闭openssh服务_关于redhat7的openssh漏洞升级修复方法
  9. 这枚纸币为什么这么贵?
  10. 【2021牛客暑期多校训练营9】E Eyjafjalla (倍增,dfs序,主席树)
  11. 适合英语学习的100部电影
  12. Android 三类框架的理解以及MVVM框架的使用
  13. ug编程内公差和外公差是什么_UG编程
  14. 【数理逻辑三】命题逻辑及形式系统【下】
  15. D3 天眼查 股权结构图
  16. 用python制作一张简单的节日贺卡
  17. python3思维导图.xmind_我常用的3款脑图工具
  18. Shell Tools and Scripting
  19. java 策略模式 促销_设计模式之策略模式
  20. c语言git代码注释风格,git代码格式化上传

热门文章

  1. 公众号改名竟是为了这个?
  2. Idea分享项目到全球最大同x交友网站gayhub居然失败了!我居然没有权限!来看看解决方法吧
  3. 如何用六年成为一个全能的机器人工程师
  4. 助创cms众筹 php,【教程】助创cms众筹系统操作流程详细说明
  5. 成都大学计算机图形学期末考试题,计算机图形学期末考试题
  6. matlab tikz,TeX系列: matlab2tikz--matlab图形数据转化为tikz命令
  7. python宿舍管理系統毕业设计源码231642
  8. Centos启动界面:You are in emergency mode
  9. 苹果用什么蓝牙耳机好?适合苹果的音乐蓝牙耳机推荐
  10. 金山WPS软件测试笔试题目总结