Quartz-JobListener解读
文章目录
- 概述
- 步骤简述
- 全局/非全局监听器
- JobListener 任务监听器 示例
- JobListener源码
- 完整示例
- 示例源码
概述
在某个所关注事件发生时,监听器提供了一种方便且非侵入性的机制来获得这一通知。Quartz 提供了三种类型的监听器:监听 Job 的,监听 Trigger 的,和监听 Scheduler 自已的。
本博文阐述如何应用每一种类型来更好的管理你的 Quartz 应用,并获悉到什么事件正在发生。
参考官方Demo:
http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/tutorial-lesson-07.html
步骤简述
要创建一个Listener, 只需要创建一个实现了org.quartz.TriggerListener或org.quartz.JobListener接口的对象即可。
在运行的时候,将Listeners注册进scheduler, 而且必须给一个name(可以通过他们的getName()方法获取Listener的name)。
除了继承接口,类也可以继承JobListenerSupport或TriggerListenerSupport,重写你感兴趣的event。
Listener通过scheduler的ListenerManager来注册,其中的Matcher 里描述哪个Jobs、Triggers需要被监听。
注意:
LListeners在运行的时候被注册进scheduler, 而不是保存在JobStore。Listener是和你的应用集成在一起的,这样每次你的应用运行的时候,都会在scheduler中重新注册listeners。
全局/非全局监听器
JobListener 和 TriggerListener 可被注册为全局或非全局监听器。
全局监听器能接收到所有的 Job/Trigger 的事件通知。
非全局监听器(或者说是一个标准的监听器) 只能接收到那些在其上已注册了监听器的 Job 或 Triiger 的事件。
你要注册你的监听器为全局或非全局的需依据你特定的应用需要。
全局监听器是主动意识的,它们为了执行它们的任务而热切的去寻找每一个可能的事件。通常全局监听器要做的工作不用指定到特定的 Job 或 Trigger。非全局监听器一般是被动意识的,它们在所关注的 Trigger 激发之前或是 Job 执行之前什么事也不做。因此,非全局的监听器比起全局监听器而言更适合于修改或增加 Job 执行的工作。这有点像知名的装饰设计模式的装饰器。
全局 监听器
scheduler.addGlobalTriggerListener(new SimpleMyTriggerListener());
非全局监听器
scheduler.addTriggerListener( triggerListener );
trigger.addTriggerListener( triggerListener.getName() );
JobListener 任务监听器 示例
JobListener源码
我们先来看下JobListener的源码:
getName() :返回一个字符串用以说明 JobListener 的名称。对于注册为全局的监听器,getName()主要用于记录日志,对于由特定 Job 引用的JobListener,注册在 JobDetail 上的监听器名称必须匹配从监听器getName() 方法的返回值。
jobToBeExecuted() :Scheduler 在 JobDetail 将要被执行时调用这个方法。
jobExecutionVetoed() :Scheduler 在 JobDetail 即将被执行,但又被 TriggerListener否决了时调用这个方法。
jobWasExecuted() :Scheduler 在 JobDetail 被执行之后调用这个方法。
自定义监听器
import org.quartz.*;public class MyJobListener implements JobListener {@Overridepublic String getName() {return "MyJobListener";}@Overridepublic void jobExecutionVetoed(JobExecutionContext arg0) {System.out.println("Job监听器:MyJobListener.jobExecutionVetoed()");}@Overridepublic void jobToBeExecuted(JobExecutionContext arg0) {System.out.println("Job监听器:MyJobListener.jobToBeExecuted()");}@Overridepublic void jobWasExecuted(JobExecutionContext arg0,JobExecutionException arg1) {System.out.println("Job监听器:MyJobListener.jobWasExecuted()");}}
注册监听器
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以后,当应用需要在某些事件发生以后去通知你的应用,这时就不需要Job去明确地去告知你的应用了。
完整示例
添加一个jobListener,监听到job1执行后,再触发一个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+ "执行时间:"+ 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+ "执行时间:"+ 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监听器* * getName() :返回一个字符串用以说明 JobListener 的名称。对于注册为全局的监听器,getName()* 主要用于记录日志,对于由特定 Job 引用的 JobListener,注册在 JobDetail* 上的监听器名称必须匹配从监听器上 getName() 方法的返回值.* * jobToBeExecuted() :Scheduler 在 JobDetail 将要被执行时调用这个方法。* * jobExecutionVetoed() :Scheduler 在 JobDetail 即将被执行,但又被* TriggerListener 否决了时调用这个方法。* * jobWasExecuted() :Scheduler 在 JobDetail 被执行之后调用这个方法。* * @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监听器:MyJobListener.jobToBeExecuted()");}@Overridepublic void jobExecutionVetoed(JobExecutionContext context) {System.out.println("Job监听器:MyJobListener.jobExecutionVetoed()");}@Overridepublic void jobWasExecuted(JobExecutionContext context,JobExecutionException jobException) {System.out.println("Job监听器:MyJobListener.jobWasExecuted()");// 设置另外一个job执行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();}}}
调度类
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();// 设置监听器JobListener jobListener = new MyJobListener();Matcher<JobKey> matcher = KeyMatcher.keyEquals(job.getKey());scheduler.getListenerManager().addJobListener(jobListener, matcher);// 将job任务加入到调度器scheduler.scheduleJob(job, trigger);// 开始任务System.out.println("------- 开始执行调度器 Scheduler ----------------");scheduler.start();try {System.out.println("------- 等待 30 秒... --------------");Thread.sleep(30L * 1000L);} catch (Exception e) {e.printStackTrace();}scheduler.shutdown(true);System.out.println("------- 关闭调度器 -----------------");SchedulerMetaData metaData = scheduler.getMetaData();System.out.println("~~~~~~~~~~ 执行了 "+ metaData.getNumberOfJobsExecuted() + " 个 jobs.");}}
运行结果
------- 初始化 ----------------------
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
------- 开始执行调度器 Scheduler ----------------
INFO QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
------- 等待 30 秒... --------------
Job监听器:MyJobListener.jobToBeExecuted()Job1 - 任务key group1.job1执行时间:2017-11-16 17:58:54
Job监听器:MyJobListener.jobWasExecuted()Job2 - 任务key DEFAULT.job2执行时间: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.
------- 关闭调度器 -----------------
~~~~~~~~~~ 执行了 2 个 jobs.
示例源码
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster
Quartz-JobListener解读相关推荐
- 关于Quartz的Job 不能被注入以及SpringAop对Job失效
关于Quartz的Job 不能被注入以及SpringAop对Job失效 Problem(问题) 最近在工作遇到需要对Quartz的Job进行异常后将异常记录到数据库的操作,第一反应就想到了使用Sp ...
- Quartz的Scheduler初始化源码分析
2019独角兽企业重金招聘Python工程师标准>>> Quartz的使用:http://donald-draper.iteye.com/blog/2321886 Quartz的S ...
- (翻译)Quartz官方教程——第七课:TriggerListeners 和 JobListeners
2019独角兽企业重金招聘Python工程师标准>>> 监听器是用来根据调度器发生的事件做出响应的对象.正如你想的那样,TriggerListeners接收触发器相关的事件,JobL ...
- Quartz定时任务学习(九)Quartz监听器
Quartz 提供了三种类型的监听器:监听 Job 的,监听 Trigger 的,和监听 Scheduler 自已的. 本章解释如何应用每一种类型来更好的管理你的 Quartz 应用,并获悉到什么事件 ...
- 项目中使用Quartz集群分享--转载
原文:http://hot66hot.iteye.com/blog/1726143 在公司分享了Quartz,发布出来,希望大家讨论补充. CRM使用Quartz集群分享 一:CRM对定时任务的依赖 ...
- quartz.properties配置文件详解
我们通常是通过quartz.properties属性配置文件(默认情况下均使用该文件)结合StdSchedulerFactory 来使用Quartz的.StdSchedulerFactory 会加载属 ...
- SpringBoot与quartz框架实现分布式定时任务
前言 quartz的分布式调度策略是以数据库为边界资源的一种异步策略.各个调度器都遵守一个基于数据库锁的操作规则从而保证了操作的唯一性. 在quartz的集群解决方案里有张表scheduler_loc ...
- quartz SpringMvc 动态定时任务(quartz2.2)
java自带定时任务可以解决部分问题但是当我们要动态执行定时任务时,quartz可以帮助我们有效解决这类型问题 代码亲测可用 springmvc中配置注入调度器scheduler,调用定时任务 < ...
- Quartz 2 定时任务(一):基本使用指南
版权声明:本文由吴仙杰创作整理,转载请注明出处:https://segmentfault.com/a/1190000009128277 1. Quartz 体系结构 Quartz 设计有三个核心类,分 ...
最新文章
- 【转】OGRE资源相关分析
- 【GAN优化】长文综述解读如何定量评价生成对抗网络(GAN)
- 2台电脑间快速复制大文件
- 权重初始化时除以前一层的神经元个数开方的意义
- 造作吧,Python快速入门!
- 查看linux可用磁盘空间_如何在Linux中检查可用磁盘空间
- pro git 阅读笔记1 基本操作
- VMware相关产品下载(随时更新)
- dm8148 开发之---4路解码器tvp5158
- python验证身份证号码大全_对身份证号码查重,你经常用的方法是错误,这个才是正确的方法...
- python第三方库文件传输助手_Python与微信——itchat包
- Unity 贴花/喷漆功能的原理、Projector组件的原理与优化
- 发货单分期发货分期收款
- 蓝桥杯 算法提高-求最大值(dp基础/类01背包+滚动数组)
- linux 进程 内存 耗光,Linux内存耗尽原因分析
- 美国计算机科学排名2010,2010年美国大学计算机科学专业研究生排名
- 某城市电话号码由三部分组成,分别是: 地区码—— 空白或三位数字; 前缀—— 非‘0’或‘1’开头的三位数字; 后缀—— 4位数字。
- 常见地类光谱信息分析-水体
- office365删除用户的onedrive内容恢复
- Css实现自适应屏幕宽度的正方形
热门文章
- kotlin 反射java类_关于Kotlin反射中实例化类的问题
- ssh 到另一台机器执行命令
- DataLoader 与 Dataset
- 信息熵和交叉熵的细节理解
- 错误解决 :Microsoft Visual C++ 14.0 is require Microsoft Visual C++ Builder 包丢失或者损坏
- 深度学习核心技术精讲100篇(四十六)-情感分析算法在阿里小蜜的应用实践
- Selenium爬携程酒店评论+jieba数据分析实战
- java 正方形字符串_java编程:怎么画一个正方形?
- Matplotlib实例教程(四)水平条形图
- Failed to get convolution algorithm.This is probably because cuDNN failed to initialize