如何在Quartz中的使用自定义的Listener
TriggerListener 是什么
TriggerListener用于接收 Trigger 触发生命周期中的事件通知,包含四类:
Trigger触发的通知
是否否决 Job 执行的决策
Trigger错过触发(misfire)的通知
Trigger执行完成的通知
与JobListener的分工:TriggerListener 关注Trigger 触发这个动作,JobListener 关注Job 执行这个动作。TriggerListener 的vetoJobExecution是**唯一能阻止 Job 执行的入口。
publicinterfaceTriggerListener{StringgetName();// 触发器名称voidtriggerFired(Triggertrigger,JobExecutionContextctx);// Trigger 触发booleanvetoJobExecution(Triggertrigger,JobExecutionContextctx);// 是否否决 Job 执行voidtriggerMisfired(Triggertrigger);// Trigger 错过触发voidtriggerComplete(Triggertrigger,JobExecutionContextctx,Trigger.CompletedExecutionInstructioninstruction);// 触发完成}也可以继承TriggerListenerSupport抽象类实现,只覆盖关注的方法,无需实现全部:
publicclassMyTriggerListenerextendsTriggerListenerSupport{@OverridepublicStringgetName(){return"myTriggerListener";}@OverridepublicvoidtriggerFired(Triggertrigger,JobExecutionContextctx){// 只关心触发事件,其他方法用默认空实现}}Trigger调用顺序
triggerMisfired(仅当 misfire 时) ↓ triggerFired ↓ vetoJobExecution ├── 返回 false(放行) │ ↓ │ JobListener.jobToBeExecuted → Job.execute() │ ↓ │ JobListener.jobWasExecuted │ ↓ │ triggerComplete │ └── 返回 true(否决) ↓ JobListener.jobExecutionVetoed ↓ triggerCompletevetoJobExecution的语义
返回
false:放行,Job 继续执行。返回
true:否决,Job不会执行;JobListener.jobToBeExecuted不触发,JobListener.jobExecutionVetoed触发。示例里打印的文字必须与返回值语义一致,不要写"被阻止了"却
return false。
示例
publicclassTestTriggerListenerimplementsTriggerListener{privatefinalStringname;publicTestTriggerListener(Stringname){this.name=name;}@OverridepublicStringgetName(){returnname;}@OverridepublicvoidtriggerFired(Triggertrigger,JobExecutionContextctx){System.out.println(name+" 触发器 "+trigger.getKey()+" 触发了");}@OverridepublicbooleanvetoJobExecution(Triggertrigger,JobExecutionContextctx){if(shouldVeto(ctx)){System.out.println(name+" 触发器 "+trigger.getKey()+" 否决本次执行");returntrue;// true = 否决,Job 不执行}returnfalse;}@OverridepublicvoidtriggerMisfired(Triggertrigger){System.out.println(name+" 触发器 "+trigger.getKey()+" 错过了触发");}@OverridepublicvoidtriggerComplete(Triggertrigger,JobExecutionContextctx,Trigger.CompletedExecutionInstructioninstruction){System.out.println(name+" 触发器 "+trigger.getKey()+" 执行完成,instruction="+instruction);}}| Matcher | 用途 |
|---|---|
KeyMatcher.keyEquals(new TriggerKey("t1", "g1")) | 精确匹配单个 TriggerKey(Trigger 用这个) |
GroupMatcher.triggerGroupEquals("g1") | 匹配整个 group 的 Trigger |
GroupMatcher.triggerGroupStartsWith("g") | 按前缀匹配 group 的 Trigger |
GroupMatcher.triggerGroupContains("g") | 按包含关系匹配 group 的 Trigger |
EverythingMatcher.allTriggers() | 匹配所有 Trigger(等价于不传 matcher) |
注意:TriggerListener 用的是TriggerKey,不是JobKey。原稿示例里传JobKey是类型错配,运行时会匹配不到任何 Trigger。
与TriggerListeners一样的,它用于接收job相关的事件,包含即将执行的任务的通知以及拒绝任务和完成任务的处理
publicinterfaceJobListener{StringgetName();//获取该JobListener的名称voidjobToBeExecuted(JobExecutionContextvar1);//Job执行前voidjobExecutionVetoed(JobExecutionContextvar1);//某个 TriggerListener.vetoJobExecution返回truevoidjobWasExecuted(JobExecutionContextvar1,JobExecutionExceptionvar2);//job完成后的处理}示例:
publicclassTestJobListenerimplementsJobListener{privateStringname;@OverridepublicStringgetName(){returnthis.name;}@OverridepublicvoidjobToBeExecuted(JobExecutionContextctx){System.out.println(ctx.getJobDetail().getKey().getName()+" 即将执行");}@OverridepublicvoidjobExecutionVetoed(JobExecutionContextctx){System.out.println(ctx.getJobDetail().getKey().getName()+" 执行被拒绝");}@OverridepublicvoidjobWasExecuted(JobExecutionContextctx,JobExecutionExceptione){if(e!=null){System.out.println(ctx.getJobDetail().getKey().getName()+" 执行异常: "+e.getMessage());}else{System.out.println(ctx.getJobDetail().getKey().getName()+" 执行完成");}}}publicvoidinit(Stringname){this.name=name;}}但是前面并没有将当我们创建了一个自己的Lsitener后如何去使用自己的Listener进行任务的调度。
如果想要让Listener被调度程序进行注册那么就必须要为其设定一个name,Listener会通过getName方法向外渲染个人的身份。
Listener在运行时间内与调度程序一起注册,并且不与jobs和触发器一起存储在JobStore中。这是因为听众通常是与应用程序的集成点。因此,每次运行应用程序时,都需要重新注册该调度程序。
注册示例:
Schedulerscheduler=schedulerFactory.getScheduler();//声名自定义监听器TestTriggerListenertestTriggerListener=newTestTriggerListener();testTriggerListener.init("testTriggerListener");TestJobListenertestJobListener=newTestJobListener();testJobListener.init("testJobListener");// 获取监听器管理器并进行监听器的注册scheduler.getListenerManager().addTriggerListener(testTriggerListener);scheduler.getListenerManager().addJobListener(testJobListener);我们也可以根据在添加时传入一个KeyMacher匹配器,只监听通过jobkey与Macher相匹配的job
scheduler.getListenerManager().addJobListener(testJobListener,KeyMatcher.keyEquals(newJobKey("testJobListener","testTriggerListener")));SchedulerListener用于监听 Scheduler 本身的事件——这些事件不一定与某个特定 Job 或 Trigger 相关,而是调度器层面的全局事件:
- Job / Trigger 的增删改(添加、调度、取消调度、删除、暂停、恢复)
- Scheduler 的生命周期(启动中、已启动、待机、关闭中、已关闭)
- 严重错误
- 调度数据被清空
publicinterfaceSchedulerListener{// ===== Job / Trigger 的增删改 =====voidjobScheduled(Triggertrigger);// Trigger 被调度(Job 被关联到 Trigger)voidjobUnscheduled(TriggerKeytriggerKey);// Trigger 被取消调度voidtriggerFinalized(Triggertrigger);// Trigger 最终化(不会再触发)voidtriggerPaused(TriggerKeytriggerKey);// 单个 Trigger 被暂停voidtriggersPaused(StringtriggerGroup);// 某组 Trigger 被暂停voidtriggerResumed(TriggerKeytriggerKey);// 单个 Trigger 被恢复voidtriggersResumed(StringtriggerGroup);// 某组 Trigger 被恢复voidjobAdded(JobDetailjobDetail);// JobDetail 被添加(addJob)voidjobDeleted(JobKeyjobKey);// JobDetail 被删除voidjobPaused(JobKeyjobKey);// 单个 Job 被暂停voidjobsPaused(StringjobGroup);// 某组 Job 被暂停voidjobResumed(JobKeyjobKey);// 单个 Job 被恢复voidjobsResumed(StringjobGroup);// 某组 Job 被恢复// ===== Scheduler 生命周期 =====voidschedulerStarting();// Scheduler 开始启动voidschedulerStarted();// Scheduler 启动完成voidschedulerInStandbyMode();// Scheduler 进入待机模式voidschedulerShuttingdown();// Scheduler 开始关闭voidschedulerShutdown();// Scheduler 关闭完成// ===== 错误 / 清空 =====voidschedulerError(Stringmsg,SchedulerExceptioncause);// Scheduler 内部严重错误voidschedulingDataCleared();// 调度数据被清空(scheduler.clear())}Scheduler 生命周期
schedulerStarting() ← start() 被调用,开始启动 ↓ schedulerStarted() ← 启动完成,开始接受调度 ↓ schedulerInStandbyMode() ← 进入待机(standby() 被调用,暂停所有触发但不关闭) ↓ schedulerShuttingdown() ← shutdown() 被调用,开始关闭 ↓ schedulerShutdown() ← 关闭完成示例
publicclassTestSchedulerListenerimplementsSchedulerListener{// ===== Job / Trigger 增删改 =====@OverridepublicvoidjobScheduled(Triggertrigger){System.out.println("[调度] Trigger 被调度: "+trigger.getKey());}@OverridepublicvoidjobUnscheduled(TriggerKeytriggerKey){System.out.println("[取消调度] Trigger: "+triggerKey);}@OverridepublicvoidtriggerFinalized(Triggertrigger){System.out.println("[最终化] Trigger 不会再触发: "+trigger.getKey());}@OverridepublicvoidtriggerPaused(TriggerKeytriggerKey){System.out.println("[暂停] Trigger: "+triggerKey);}@OverridepublicvoidtriggersPaused(StringtriggerGroup){System.out.println("[暂停] Trigger 组: "+triggerGroup);}@OverridepublicvoidtriggerResumed(TriggerKeytriggerKey){System.out.println("[恢复] Trigger: "+triggerKey);}@OverridepublicvoidtriggersResumed(StringtriggerGroup){System.out.println("[恢复] Trigger 组: "+triggerGroup);}@OverridepublicvoidjobAdded(JobDetailjobDetail){System.out.println("[添加] JobDetail: "+jobDetail.getKey());}@OverridepublicvoidjobDeleted(JobKeyjobKey){System.out.println("[删除] JobDetail: "+jobKey);}@OverridepublicvoidjobPaused(JobKeyjobKey){System.out.println("[暂停] Job: "+jobKey);}@OverridepublicvoidjobsPaused(StringjobGroup){System.out.println("[暂停] Job 组: "+jobGroup);}@OverridepublicvoidjobResumed(JobKeyjobKey){System.out.println("[恢复] Job: "+jobKey);}@OverridepublicvoidjobsResumed(StringjobGroup){System.out.println("[恢复] Job 组: "+jobGroup);}@OverridepublicvoidschedulerStarting(){System.out.println("[生命周期] Scheduler 启动中");}@OverridepublicvoidschedulerStarted(){System.out.println("[生命周期] Scheduler 已启动");}@OverridepublicvoidschedulerInStandbyMode(){System.out.println("[生命周期] Scheduler 进入待机模式");}@OverridepublicvoidschedulerShuttingdown(){System.out.println("[生命周期] Scheduler 关闭中");}@OverridepublicvoidschedulerShutdown(){System.out.println("[生命周期] Scheduler 已关闭");}@OverridepublicvoidschedulerError(Stringmsg,SchedulerExceptioncause){System.out.println("[错误] "+msg+" | "+cause.getMessage());}@OverridepublicvoidschedulingDataCleared(){System.out.println("[清空] 调度数据已清空");}}他的注册方式也是通过scheduler进行获取Manager然后进行注册
Schedulerscheduler=schedulerFactory.getScheduler();scheduler.getListenerManager().addSchedulerListener(newTestSchedulerListener());注意:addSchedulerListener没有 Matcher 重载——SchedulerListener 是全局的,所有 Scheduler 级别的事件都会通知到它。这与addJobListener/addTriggerListener支持 Matcher 不同。
三种 Listener 协作关系总览
| 事件 | JobListener | TriggerListener | SchedulerListener |
|---|---|---|---|
调用scheduleJob | — | — | jobScheduled |
| Trigger 触发 | — | triggerFired | — |
| 是否否决执行 | — | vetoJobExecution | — |
| Job 即将执行 | jobToBeExecuted | — | — |
| Job 被否决 | jobExecutionVetoed | — | — |
| Job 执行完成 | jobWasExecuted | — | — |
| Trigger 触发完成 | — | triggerComplete | — |
| Trigger misfire | — | triggerMisfired | — |
| Trigger 不再触发 | — | — | triggerFinalized |
调用deleteJob | — | — | jobDeleted |
| Scheduler 启动/关闭 | — | — | schedulerStarted/schedulerShutdown |