Quartz-JobListener解读
文章目錄
- 概述
- 步驟簡述
- 全局/非全局監(jiān)聽器
- JobListener 任務監(jiān)聽器 示例
- JobListener源碼
- 完整示例
- 示例源碼
概述
在某個所關(guān)注事件發(fā)生時,監(jiān)聽器提供了一種方便且非侵入性的機制來獲得這一通知。Quartz 提供了三種類型的監(jiān)聽器:監(jiān)聽 Job 的,監(jiān)聽 Trigger 的,和監(jiān)聽 Scheduler 自已的。
本博文闡述如何應用每一種類型來更好的管理你的 Quartz 應用,并獲悉到什么事件正在發(fā)生。
參考官方Demo:
http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/tutorial-lesson-07.html
步驟簡述
要創(chuàng)建一個Listener, 只需要創(chuàng)建一個實現(xiàn)了org.quartz.TriggerListener或org.quartz.JobListener接口的對象即可。
在運行的時候,將Listeners注冊進scheduler, 而且必須給一個name(可以通過他們的getName()方法獲取Listener的name)。
除了繼承接口,類也可以繼承JobListenerSupport或TriggerListenerSupport,重寫你感興趣的event。
Listener通過scheduler的ListenerManager來注冊,其中的Matcher 里描述哪個Jobs、Triggers需要被監(jiān)聽。
注意:
LListeners在運行的時候被注冊進scheduler, 而不是保存在JobStore。Listener是和你的應用集成在一起的,這樣每次你的應用運行的時候,都會在scheduler中重新注冊listeners。
全局/非全局監(jiān)聽器
JobListener 和 TriggerListener 可被注冊為全局或非全局監(jiān)聽器。
-
全局監(jiān)聽器能接收到所有的 Job/Trigger 的事件通知。
-
非全局監(jiān)聽器(或者說是一個標準的監(jiān)聽器) 只能接收到那些在其上已注冊了監(jiān)聽器的 Job 或 Triiger 的事件。
你要注冊你的監(jiān)聽器為全局或非全局的需依據(jù)你特定的應用需要。
全局監(jiān)聽器是主動意識的,它們?yōu)榱藞?zhí)行它們的任務而熱切的去尋找每一個可能的事件。通常全局監(jiān)聽器要做的工作不用指定到特定的 Job 或 Trigger。非全局監(jiān)聽器一般是被動意識的,它們在所關(guān)注的 Trigger 激發(fā)之前或是 Job 執(zhí)行之前什么事也不做。因此,非全局的監(jiān)聽器比起全局監(jiān)聽器而言更適合于修改或增加 Job 執(zhí)行的工作。這有點像知名的裝飾設(shè)計模式的裝飾器。
全局 監(jiān)聽器
scheduler.addGlobalTriggerListener(new SimpleMyTriggerListener());非全局監(jiān)聽器
scheduler.addTriggerListener( triggerListener ); trigger.addTriggerListener( triggerListener.getName() );JobListener 任務監(jiān)聽器 示例
JobListener源碼
我們先來看下JobListener的源碼:
-
getName() :返回一個字符串用以說明 JobListener 的名稱。對于注冊為全局的監(jiān)聽器,getName()主要用于記錄日志,對于由特定 Job 引用的JobListener,注冊在 JobDetail 上的監(jiān)聽器名稱必須匹配從監(jiān)聽器getName() 方法的返回值。
-
jobToBeExecuted() :Scheduler 在 JobDetail 將要被執(zhí)行時調(diào)用這個方法。
-
jobExecutionVetoed() :Scheduler 在 JobDetail 即將被執(zhí)行,但又被 TriggerListener否決了時調(diào)用這個方法。
-
jobWasExecuted() :Scheduler 在 JobDetail 被執(zhí)行之后調(diào)用這個方法。
自定義監(jiān)聽器
import org.quartz.*;public class MyJobListener implements JobListener {@Overridepublic String getName() {return "MyJobListener";}@Overridepublic void jobExecutionVetoed(JobExecutionContext arg0) {System.out.println("Job監(jiān)聽器:MyJobListener.jobExecutionVetoed()");}@Overridepublic void jobToBeExecuted(JobExecutionContext arg0) {System.out.println("Job監(jiān)聽器:MyJobListener.jobToBeExecuted()");}@Overridepublic void jobWasExecuted(JobExecutionContext arg0,JobExecutionException arg1) {System.out.println("Job監(jiān)聽器:MyJobListener.jobWasExecuted()");}}注冊監(jiān)聽器
MyJobListener myJobListener=new MyJobListener(); // 添加一個特定的job scheduler.getListenerManager().addJobListener(myJobListener, KeyMatcher.jobKeyEquals(new JobKey("myJobName", "myJobGroup")));上面的代碼就可以變成:
scheduler.getListenerManager().addJobListener(myJobListener, jobKeyEquals(jobKey("myJobName", "myJobGroup")));// 添加特定組的所有jobs scheduler.getListenerManager().addJobListener(myJobListener, jobGroupEquals("myJobGroup"));// 添加多個特定組的所有jobs scheduler.getListenerManager().addJobListener(myJobListener, or(jobGroupEquals("myJobGroup"), jobGroupEquals("yourGroup")));// 添加所有jobs scheduler.getListenerManager().addJobListener(myJobListener, allJobs());有了Listeners以后,當應用需要在某些事件發(fā)生以后去通知你的應用,這時就不需要Job去明確地去告知你的應用了。
完整示例
添加一個jobListener,監(jiān)聽到j(luò)ob1執(zhí)行后,再觸發(fā)一個job2任務
Job1.java
package com.xgj.quartz.quartzItself.listener.jobListener;import java.text.SimpleDateFormat; import java.util.Date;import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey;public class Job1 implements Job {public void execute(JobExecutionContext context)throws JobExecutionException {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");JobKey jobKey = context.getJobDetail().getKey();System.out.println("\nJob1 - 任務key "+ jobKey+ "執(zhí)行時間:"+ sdf.format(new Date()));} }Job2.java
package com.xgj.quartz.quartzItself.listener.jobListener;import java.text.SimpleDateFormat; import java.util.Date;import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey;public class Job2 implements Job {public void execute(JobExecutionContext context)throws JobExecutionException {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");JobKey jobKey = context.getJobDetail().getKey();System.err.println("\nJob2 - 任務key "+ jobKey+ "執(zhí)行時間:"+ sdf.format(new Date()));} }自定義JobListener
package com.xgj.quartz.quartzItself.listener.jobListener;import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobListener; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerBuilder;/*** * * @ClassName: MyJobListener* * @Description: 自定義Job監(jiān)聽器* * getName() :返回一個字符串用以說明 JobListener 的名稱。對于注冊為全局的監(jiān)聽器,getName()* 主要用于記錄日志,對于由特定 Job 引用的 JobListener,注冊在 JobDetail* 上的監(jiān)聽器名稱必須匹配從監(jiān)聽器上 getName() 方法的返回值.* * jobToBeExecuted() :Scheduler 在 JobDetail 將要被執(zhí)行時調(diào)用這個方法。* * jobExecutionVetoed() :Scheduler 在 JobDetail 即將被執(zhí)行,但又被* TriggerListener 否決了時調(diào)用這個方法。* * jobWasExecuted() :Scheduler 在 JobDetail 被執(zhí)行之后調(diào)用這個方法。* * @author: Mr.Yang* * @date: 2017年11月16日 下午3:57:35*/ public class MyJobListener implements JobListener {@Overridepublic String getName() {return "MyJobListerner";}@Overridepublic void jobToBeExecuted(JobExecutionContext context) {System.out.println("Job監(jiān)聽器:MyJobListener.jobToBeExecuted()");}@Overridepublic void jobExecutionVetoed(JobExecutionContext context) {System.out.println("Job監(jiān)聽器:MyJobListener.jobExecutionVetoed()");}@Overridepublic void jobWasExecuted(JobExecutionContext context,JobExecutionException jobException) {System.out.println("Job監(jiān)聽器:MyJobListener.jobWasExecuted()");// 設(shè)置另外一個job執(zhí)行JobDetail job2 = JobBuilder.newJob(Job2.class).withIdentity("job2").build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity("job2Trigger").startNow().build();try {context.getScheduler().scheduleJob(job2, trigger);} catch (SchedulerException e) {System.err.println("無法安排job2!");e.printStackTrace();}}}調(diào)度類
package com.xgj.quartz.quartzItself.listener.jobListener;import static org.quartz.JobBuilder.newJob; import static org.quartz.TriggerBuilder.newTrigger;import org.quartz.JobDetail; import org.quartz.JobKey; import org.quartz.JobListener; import org.quartz.Matcher; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.SchedulerMetaData; import org.quartz.Trigger; import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.matchers.KeyMatcher;public class JobListenerDemo {public static void main(String[] args) throws Exception {System.out.println("------- 初始化 ----------------------");// SchedulerSchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();// JobJobDetail job = newJob(Job1.class).withIdentity("job1", "group1").build();// Tirgger Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startNow().build();// 設(shè)置監(jiān)聽器JobListener jobListener = new MyJobListener();Matcher<JobKey> matcher = KeyMatcher.keyEquals(job.getKey());scheduler.getListenerManager().addJobListener(jobListener, matcher);// 將job任務加入到調(diào)度器scheduler.scheduleJob(job, trigger);// 開始任務System.out.println("------- 開始執(zhí)行調(diào)度器 Scheduler ----------------");scheduler.start();try {System.out.println("------- 等待 30 秒... --------------");Thread.sleep(30L * 1000L);} catch (Exception e) {e.printStackTrace();}scheduler.shutdown(true);System.out.println("------- 關(guān)閉調(diào)度器 -----------------");SchedulerMetaData metaData = scheduler.getMetaData();System.out.println("~~~~~~~~~~ 執(zhí)行了 "+ metaData.getNumberOfJobsExecuted() + " 個 jobs.");}}運行結(jié)果
------- 初始化 ---------------------- INFO StdSchedulerFactory - Using default implementation for ThreadExecutor INFO SimpleThreadPool - Job execution threads will use class loader of thread: main INFO SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl INFO QuartzScheduler - Quartz Scheduler v.2.2.3 created. INFO RAMJobStore - RAMJobStore initialized. INFO QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.2.3) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.NOT STARTED.Currently in standby mode.Number of jobs executed: 0Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.INFO StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties' INFO StdSchedulerFactory - Quartz scheduler version: 2.2.3 ------- 開始執(zhí)行調(diào)度器 Scheduler ---------------- INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started. ------- 等待 30 秒... -------------- Job監(jiān)聽器:MyJobListener.jobToBeExecuted()Job1 - 任務key group1.job1執(zhí)行時間:2017-11-16 17:58:54 Job監(jiān)聽器:MyJobListener.jobWasExecuted()Job2 - 任務key DEFAULT.job2執(zhí)行時間:2017-11-16 17:58:54 INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down. INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused. INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete. ------- 關(guān)閉調(diào)度器 ----------------- ~~~~~~~~~~ 執(zhí)行了 2 個 jobs.示例源碼
代碼已托管到Github—> https://github.com/yangshangwei/SpringMaster
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Quartz-JobListener解读的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Quartz-DateBuilder解读
- 下一篇: Quartz-TriggerListen