1、概念
Quartz的监听器用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知。类似于任务执行过程中的邮件、短信类的提醒。Quartz监听器主要由JobListener、TriggerListener、SchedulerListener三种,顾名思义,分布表示任务、触发器、调度器对应的监听器。三者的使用方法类似,在开始介绍三种监听器之前,需要明确两个概念:全局监听器与非全局监听器,二者的区别在于:
全局监听器能够接收到所有的Job/Trigger的事件通知
而非全局监听器只能接收到在其上注册的Job或者Trigger的事件,不在其上注册的Job或Trigger则不会进行监听。
本课程关于全局与非全局的监听器的使用,将一一介绍。
2、JobListener
任务调度过程中,与任务Job相关的事件包括:Job开始要执行的提示;Job执行完成的提示等。
publicinterfaceJobListener {
public String getName();
publicvoidjobToBeExecuted(JobExecutionContext context);
publicvoidjobExecutionVetoed(JobExecutionContext context);
publicvoidjobWasExecuted(JobExecutionContext context, JobExecutionException jobException);
}
复制代码
其中:
. getName方法:用于获取该JobListener的名称。. jobToBeExecuted方法:Scheduler在JobDetail将要被执行时调用这个方法。. jobExecutionVetoed方法:Scheduler在JobDetail即将被执行,但又被TriggerListener否决时会调用该方法。. jobWasExecuted方法:Scheduler在JobDetail被执行之后调用这个方法。
示例:
HelloJobListener.java
// 定义任务类publicclassHelloJobListenerimplementsJob {
@Overridepublicvoidexecute(JobExecutionContext context)throws JobExecutionException {
// 输出当前时间Datedate=newDate();
SimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
StringdateString= dateFormat.format(date);
// 工作内容
System.out.println("正在进行数据库的备份工作,备份数据库的时间是:" +dateString);
}
}
复制代码
创建自定义的JobListener
MyJobListener.java
publicclassMyJobListenerimplementsJobListener {
@Overridepublic String getName() {
Stringname=this.getClass().getSimpleName();
System.out.println("监听器的名称是:" +name);
return name;
}
@OverridepublicvoidjobToBeExecuted(JobExecutionContext context) {
Stringname= context.getJobDetail().getKey().getName();
System.out.println("Job的名称是:" +name + " Scheduler在JobDetail将要被执行时调用的方法");
}
@OverridepublicvoidjobExecutionVetoed(JobExecutionContext context) {
Stringname= context.getJobDetail().getKey().getName();
System.out.println("Job的名称是:" +name + " Scheduler在JobDetail即将被执行,但又被TriggerListener否决时会调用该方法");
}
@OverridepublicvoidjobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
Stringname= context.getJobDetail().getKey().getName();
System.out.println("Job的名称是:" +name + " Scheduler在JobDetail被执行之后调用这个方法");
}
}
复制代码
执行调度器
HelloSchedulerDemoJobListener.java
publicclassHelloSchedulerDemoJobListener {
publicstaticvoidmain(String[] args)throws Exception {
// 1、调度器(Scheduler),从工厂中获取调度的实例(默认:实例化new StdSchedulerFactory();)Schedulerscheduler= StdSchedulerFactory.getDefaultScheduler();
// 2、任务实例(JobDetail)定义一个任务调度实例,将该实例与HelloJobSimpleTrigger绑定,任务类需要实现Job接口JobDetailjobDetail= JobBuilder.newJob(HelloJobListener.class) // 加载任务类,与HelloJob完成绑定,要求HelloJob实现Job接口
.withIdentity("job1", "group1") // 参数1:任务的名称(唯一实例);参数2:任务组的名称
.build();
// 3、触发器(Trigger)定义触发器,马上执行,然后每5秒重复执行一次Triggertrigger= TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 参数1:触发器的名称(唯一实例);参数2:触发器组的名称
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatSecondlyForever(5).withRepeatCount(2)) // 每5秒执行一次,连续执行3次后停止,默认是0
.build();
// 4、让调度器关联任务和触发器,保证按照触发器定义的调整执行任务
scheduler.scheduleJob(jobDetail, trigger);
// 创建并注册一个全局的Job Listener// scheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());// 创建并注册一个局部的Job Listener,表示指定的任务Job
scheduler.getListenerManager().addJobListener(newMyJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("job1", "group1")));
// 5、启动
scheduler.start();
// 关闭//scheduler.shutdown();
}
}
复制代码
3、TriggerListener
任务调度过程中,与触发器Trigger相关的事件包括:触发器触发、触发器未正确触发、触发器完成等。
publicinterfaceTriggerListener {
public String getName();
publicvoidtriggerFired(Trigger trigger, JobExecutionContext context);
publicbooleanvetoJobExecution(Trigger trigger, JobExecutionContext context);
publicvoidtriggerMisfired(Trigger trigger);
publicvoidtriggerComplete(Trigger trigger, JobExecutionContext context, CompletedExecutionInstruction triggerInstructionCode)
}
复制代码
其中:
. getName方法:用于获取触发器的名称。. triggerFired方法:当与监听器关联的Trigger被触发,Job上的Execute()方法将被执行时,Scheduler就调用该方法。. vetoJobExecution方法:在Trigger触发后,Job将要执行时由Scheduler调用这个方法。TriggerListener给了一个选择去否决Job的执行。假如这个方法返回true,这个Job将不会为此次Trigger触发而得到执行。. triggerMisfired方法:Scheduler调用这个方法是在Trigger错过触发时。你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的Trigger时,长逻辑会导致骨牌效应。你应当保持这个方法尽量的小。. triggerComplete方法:Trigger被触发并且完成了Job的执行时,Scheduler调用这个方法。
示例:
下面的例子简单展示了TriggerListener的使用,其中创建并注册TriggerListener与JobListener几乎类似。
HelloJobListener.java
// 定义任务类publicclassHelloJobListenerimplementsJob {
@Overridepublicvoidexecute(JobExecutionContext context)throws JobExecutionException {
// 输出当前时间Datedate=newDate();
SimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
StringdateString= dateFormat.format(date);
// 工作内容
System.out.println("正在进行数据库的备份工作,备份数据库的时间是:" +dateString);
}
}
复制代码
MyTriggerListener.java
publicclassMyTriggerListenerimplementsTriggerListener {
private String name;
// 构造方法,自定义传递触发器的名称,默认是类的名称publicMyTriggerListener(String name) {
super();
this.name = name;
}
@Overridepublic String getName() {
returnthis.name; // 不返还会抛出一个名称为空的异常
}
// @Override// public String getName() {// String name = this.getClass().getSimpleName();// System.out.println("触发器的名称:" +name);// return name; // 不返还会抛出一个名称为空的异常// }@OverridepublicvoidtriggerFired(Trigger trigger, JobExecutionContext context) {
Stringname=this.getClass().getSimpleName();
System.out.println(name +"被触发");
}
@OverridepublicbooleanvetoJobExecution(Trigger trigger, JobExecutionContext context) {
Stringname=this.getClass().getSimpleName();
// TriggerListener给了一个选择去否决Job的执行。假如这个方法返回true,这个Job将不会为此次Trigger触发而得到执行。
System.out.println(name +" 没有被触发");
returnfalse; // true:表示不会执行Job的方法
}
@OverridepublicvoidtriggerMisfired(Trigger trigger) {
Stringname=this.getClass().getSimpleName();
// Scheduler调用这个方法是在Trigger错过触发时
System.out.println(name +" 错过触发");
}
@OverridepublicvoidtriggerComplete(Trigger trigger, JobExecutionContext context,
CompletedExecutionInstruction triggerInstructionCode) {
Stringname=this.getClass().getSimpleName();
// Trigger被触发并且完成了Job的执行时,Scheduler调用这个方法。
System.out.println(name +" 完成之后触发");
}
}
复制代码
HelloSchedulerDemoTriggerListener.java
publicclassHelloSchedulerDemoTriggerListener {
publicstaticvoidmain(String[] args)throws Exception {
// 1、调度器(Scheduler),从工厂中获取调度的实例(默认:实例化new StdSchedulerFactory();)Schedulerscheduler= StdSchedulerFactory.getDefaultScheduler();
// 2、任务实例(JobDetail)定义一个任务调度实例,将该实例与HelloJobSimpleTrigger绑定,任务类需要实现Job接口JobDetailjobDetail= JobBuilder.newJob(HelloJobListener.class) // 加载任务类,与HelloJob完成绑定,要求HelloJob实现Job接口
.withIdentity("job1", "group1") // 参数1:任务的名称(唯一实例);参数2:任务组的名称
.build();
// 3、触发器(Trigger)定义触发器,马上执行,然后每5秒重复执行一次Triggertrigger= TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 参数1:触发器的名称(唯一实例);参数2:触发器组的名称
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatSecondlyForever(5).withRepeatCount(2)) // 每5秒执行一次,连续执行3次后停止,默认是0
.build();
// 4、让调度器关联任务和触发器,保证按照触发器定义的调整执行任务
scheduler.scheduleJob(jobDetail, trigger);
// 创建并注册一个全局的Trigger Listener// scheduler.getListenerManager().addTriggerListener(new MyTriggerListener(), EverythingMatcher.allTriggers());// 创建并注册一个局部的Trigger Listener
scheduler.getListenerManager().addTriggerListener(newMyTriggerListener(), KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1", "group1")));
// 5、启动
scheduler.start();
// 关闭//scheduler.shutdown();
}
}
复制代码
4、SchedulerListener
SchedulerListener会在Scheduler的生命周期中关键事件发生时被调用。与Scheduler有关的事件包括:增加一个Job/Trigger,删除一个Job/Trigger,Scheduler发生严重错误,关闭Scheduler等。
publicinterfaceSchedulerListener {
publicvoidjobScheduled(Trigger trigger);
publicvoidjobUnscheduled(TriggerKey triggerKey);
publicvoidtriggerFinalized(Trigger trigger);
publicvoidtriggersPaused(String triggerGroup);
publicvoidtriggersResumed(String triggerGroup);
publicvoidjobsPaused(String jobGroup);
publicvoidjobsResumed(String jobGroup);
publicvoidschedulerError(String msg, SchedulerException cause);
publicvoidschedulerStarted();
publicvoidschedulerInStandbyMode();
publicvoidschedulerShutdown();
publicvoidschedulingDataCleared()
}
复制代码
其中:
. jobScheduled方法:用于部署JobDetail时调用。. jobUnscheduled方法:用于卸载JobDetail时调用。. triggerFinalized方法:当一个Trigger来到了再也不会触发的状态时调用这个方法。除非这个Job已设置成了持久性,否则它就会从Scheduler中移除。. triggersPaused方法:Scheduler调用这个方法是发生在一个Trigger或Trigger组被暂停时。假如是Trigger组的话,triggerName参数将为null。. triggersResumed方法:Scheduler调用这个方法是发生在一个Trigger或Trigger组从暂停中恢复时。假如是Trigger组的话,triggerName参数将为null。. jobsPaused方法:当一个或一组JobDetail暂停时调用这个方法。. jobsResumed方法:当一个或一组Job从暂停上恢复时调用这个方法。假如是一个Job组,jobName将为null。. schedulerError方法:在Scheduler的正常运行期间产生一个严重错误时调用这个方法。. schedulerStarted方法:当Scheduler开启时,调用该方法。. schedulerInStandbyMode方法:当Scheduler处于StandBy模式时,调用该方法。. schedulerShutdown方法:当Scheduler停止时,调用该方法。. schedulingDataCleared方法:当Scheduler中的数据被清除时,调用该方法。
示例:
下面的代码简单描述了如何使用SchedulerListener方法:
HelloJobListener.java
// 定义任务类publicclassHelloJobListenerimplementsJob {
@Overridepublicvoidexecute(JobExecutionContext context)throws JobExecutionException {
// 输出当前时间Datedate=newDate();
SimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
StringdateString= dateFormat.format(date);
// 工作内容
System.out.println("正在进行数据库的备份工作,备份数据库的时间是:" +dateString);
}
}
复制代码
MySchedulerListener.java
publicclassMySchedulerListenerimplementsSchedulerListener {
@OverridepublicvoidjobScheduled(Trigger trigger) {
Stringname= trigger.getKey().getName();
// 用于部署JobDetail时调用
System.out.println(name +" 完成部署");
}
@OverridepublicvoidjobUnscheduled(TriggerKey triggerKey) {
Stringname= triggerKey.getName();
// 用于卸载JobDetail时调用
System.out.println(name +" 完成卸载");
}
@OverridepublicvoidtriggerFinalized(Trigger trigger) {
Stringname= trigger.getKey().getName();
// 当一个Trigger来到了再也不会触发的状态时调用这个方法。除非这个Job已设置成了持久性,否则它就会从Scheduler中移除。
System.out.println(name +" 触发器被移除");
}
@OverridepublicvoidtriggerPaused(TriggerKey triggerKey) {
Stringname= triggerKey.getName();
// Scheduler调用这个方法是发生在一个Trigger或Trigger组被暂停时。假如是Trigger组的话,triggerName参数将为null。
System.out.println(name +" 正在被暂停");
}
@OverridepublicvoidtriggersPaused(String triggerGroup) {
// Scheduler调用这个方法是发生在一个Trigger或Trigger组被暂停时。假如是Trigger组的话,triggerName参数将为null。
System.out.println("触发器组" +triggerGroup +" 正在被暂停");
}
@OverridepublicvoidtriggerResumed(TriggerKey triggerKey) {
// Scheduler调用这个方法是发生在一个Trigger或Trigger组从暂停中恢复时。假如是Trigger组的话,triggerName参数将为null。参数将为null。Stringname= triggerKey.getName();
System.out.println(name +" 正在从暂停中恢复");
}
@OverridepublicvoidtriggersResumed(String triggerGroup) {
// Scheduler调用这个方法是发生在一个Trigger或Trigger组从暂停中恢复时。假如是Trigger组的话,triggerName参数将为null。参数将为null。
System.out.println("触发器组" +triggerGroup +" 正在从暂停中恢复");
}
@OverridepublicvoidjobAdded(JobDetail jobDetail) {
//
System.out.println(jobDetail.getKey() +" 添加工作任务");
}
@OverridepublicvoidjobDeleted(JobKey jobKey) {
//
System.out.println(jobKey +" 删除工作任务");
}
@OverridepublicvoidjobPaused(JobKey jobKey) {
//
System.out.println(jobKey +" 工作任务正在被暂停");
}
@OverridepublicvoidjobsPaused(String jobGroup) {
//
System.out.println("工作组" +jobGroup +" 正在被暂停");
}
@OverridepublicvoidjobResumed(JobKey jobKey) {
//
System.out.println(jobKey +" 正在从暂停中恢复");
}
@OverridepublicvoidjobsResumed(String jobGroup) {
//
System.out.println("工作组" +jobGroup +" 正在从暂停中恢复");
}
@OverridepublicvoidschedulerError(String msg, SchedulerException cause) {
// 在Scheduler的正常运行期间产生一个严重错误时调用这个方法。
System.out.println("产生严重错误的时候调用" +msg +" " +cause.getUnderlyingException());
}
@OverridepublicvoidschedulerInStandbyMode() {
// 当Scheduler处于StandBy模式时,调用该方法。
System.out.println("调度器被挂起模式的时候调用");
}
@OverridepublicvoidschedulerStarted() {
// 当Scheduler开启时,调用该方法
System.out.println("调度器开启的时候调用");
}
@OverridepublicvoidschedulerStarting() {
//
System.out.println("调度器正在开启的时候调用");
}
@OverridepublicvoidschedulerShutdown() {
//
System.out.println("调度器关闭的时候调用");
}
@OverridepublicvoidschedulerShuttingdown() {
//
System.out.println("调度器正在关闭的时候调用");
}
@OverridepublicvoidschedulingDataCleared() {
// 当Scheduler中的数据被清除时,调用该方法
System.out.println("调度器数据被清除的时候调用");
}
}
复制代码
HelloSchedulerDemoTriggerListener.java
publicclassHelloSchedulerDemoTriggerListener {
publicstaticvoidmain(String[] args)throws Exception {
// 1、调度器(Scheduler),从工厂中获取调度的实例(默认:实例化new StdSchedulerFactory();)Schedulerscheduler= StdSchedulerFactory.getDefaultScheduler();
// 2、任务实例(JobDetail)定义一个任务调度实例,将该实例与HelloJobSimpleTrigger绑定,任务类需要实现Job接口JobDetailjobDetail= JobBuilder.newJob(HelloJobListener.class) // 加载任务类,与HelloJob完成绑定,要求HelloJob实现Job接口
.withIdentity("job1", "group1") // 参数1:任务的名称(唯一实例);参数2:任务组的名称
.build();
// 3、触发器(Trigger)定义触发器,马上执行,然后每5秒重复执行一次Triggertrigger= TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 参数1:触发器的名称(唯一实例);参数2:触发器组的名称
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatSecondlyForever(5).withRepeatCount(2)) // 每5秒执行一次,连续执行3次后停止,默认是0
.build();
// 4、让调度器关联任务和触发器,保证按照触发器定义的调整执行任务
scheduler.scheduleJob(jobDetail, trigger);
// 创建调度器的监听
scheduler.getListenerManager().addSchedulerListener(newMySchedulerListener());
// 移除对应的调度器的监听// scheduler.getListenerManager().removeSchedulerListener(new MySchedulerListener());// 5、启动
scheduler.start();
// 线程延迟7秒后关闭
Thread.sleep(7000L);
// 关闭
scheduler.shutdown();
}
}