前言

和许多框架类似,quartz也提供了监听器即listener的功能,通过监听器可以达到在被调度的任务之前,之后,或者任务执行过程中,得到人为的干预的效果,举例来说,我们希望在某个job执行前过滤一部分数据,或者在job完成时给系统管理员发一封邮件,甚至我们希望调度任务跳过节假日的执行等,在类似的业务场景下,我们就可以考虑使用quartz提供的监听器功能

Quartz监听器类型

Quartz主要提供了3种类型的监听器,分别是

JobListener、TriggerListener、SchedulerListener三种,顾名思义,可分别理解为任务、触发器、调度器对应的监听器

三者的使用方法类似,quartz提供了各自的接口,我们只需要实现相应的方法即可。

在开始介绍三种监听器之前,需要掌握两个概念:全局监听器与非全局监听器,二者的区别在于:全局监听器能够接收到所有的Job/Trigger的事件通知,非全局监听器只能接收到在其上注册的Job或Trigger的事件,不在其上注册的Job或Trigger则不会进行监听。这个在:scheduler.getListenerManager().addJobListener 对应的API中会得到体现,下面通过代码分别演示下各个监听器的使用

1、JobListener

JobListener是一个接口,里面提供了几个方法,完整的接口如下:

public interface JobListener {String getName();void jobToBeExecuted(JobExecutionContext var1);void jobExecutionVetoed(JobExecutionContext var1);void jobWasExecuted(JobExecutionContext var1, JobExecutionException var2);
}
  • getName方法:用于获取该JobListener的名称
  • jobToBeExecuted方法:Scheduler在JobDetail将要被执行时调用这个方法
  • jobExecutionVetoed方法:Scheduler在JobDetail即将被执行,但又被TriggerListerner否决时会调用该方法
  • jobWasExecuted方法:Scheduler在JobDetail被执行之后调用这个方法

演示demo


@Slf4j
public class MyJobTriggerListener implements JobListener {/*** 获取job名称* @return*/@Overridepublic String getName() {String name = getClass().getSimpleName();log.info(name);return name;}/*** job将要被执行时调用的方法* @param jobExecutionContext*/@Overridepublic void jobToBeExecuted(JobExecutionContext jobExecutionContext) {log.info("2 ===  jobToBeExecuted");}@Overridepublic void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {System.out.println("jobExecutionVetoed");}/*** job执行完毕之后执行的方法* @param jobExecutionContext* @param e*/@Overridepublic void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {log.info("5 ========== jobWasExecuted");}
}
public class DemoTest1 {private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();public static void main(String[] args) throws Exception {Scheduler scheduler = schedulerFactory.getScheduler();JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("myJob", "myJobGroup")//.requestRecovery() // 执行中应用发生故障,需要重新执行.build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myFirstTrigger", "myFirstTriggerGroup").startNow().withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?")).build();//关联job和trigger对象scheduler.scheduleJob(job, trigger);scheduler.getListenerManager().addJobListener(new MyJobTriggerListener(), EverythingMatcher.allJobs());if(!scheduler.isShutdown()){scheduler.start();}}
}

最后再提供一个实现job接口的类即可

@Slf4j
public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info("job task begin");}
}

本段代码基本上没有什么逻辑,仅仅就是在之前的demo篇的最后,通过scheduler这个对象将监听器调用起来即可,运行这段代码,观察控制台效果,

个人理解,其实把监听器类比servlet的生命周期函数可能更好理解,即在job执行之前,之后或者执行过程中动态去添加一些额外的动作

2、TriggerListener

triggerListener中的方法稍微多一些

public interface TriggerListener {String getName();void triggerFired(Trigger var1, JobExecutionContext var2);boolean vetoJobExecution(Trigger var1, JobExecutionContext var2);void triggerMisfired(Trigger var1);void triggerComplete(Trigger var1, JobExecutionContext var2, CompletedExecutionInstruction var3);
}

简单解释下几个方法:

  • triggerFired方法:当与监听器相关联的Trigger被触发,Job上的execute()方法将被执行时,Scheduler就调用该方法
  • vetoJobExecution方法:在 Trigger 触发后,Job 将要被执行时由 Scheduler 调用这个方法。TriggerListener 给了一个选择去否决 Job 的执行。假如这个方法返回 true,这个 Job 将不会为此次 Trigger 触发而得到执行
  • triggerMisfired方法:Scheduler 调用这个方法是在 Trigger 错过触发时。你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的 Trigger 时,长逻辑会导致骨牌效应。你应当保持这上方法尽量的小
  • triggerComplete方法:Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个方法

总体的使用和jobTrigger类似,下面看具体代码,

public class TriggerListener1 implements TriggerListener {Logger logger = LoggerFactory.getLogger(TriggerListener1.class);private String timerTriggerName = "";public TriggerListener1(String timerTriggerName) {this.timerTriggerName = timerTriggerName;}@Overridepublic String getName() {logger.info("1 -----> 触发器名称 :" + timerTriggerName);return timerTriggerName;}@Overridepublic void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {logger.info("2 -----> Trigger被激发 它关联的job即将被运行");}@Overridepublic boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {return false;}@Overridepublic void triggerMisfired(Trigger trigger) {logger.info("触发器错过执行时候被执行");}@Overridepublic void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {logger.info("5 ====== triggerComplete ----------");}}
public class DemoTest2 {private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();public static void main(String[] args) throws Exception{Scheduler scheduler = schedulerFactory.getScheduler();JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("myJob1", "myJobGroup1")//.requestRecovery() // 执行中应用发生故障,需要重新执行.build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myFirstTrigger1", "myFirstTriggerGroup1").startNow().withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?")).build();scheduler.scheduleJob(job, trigger);scheduler.getListenerManager().addTriggerListener(new TriggerListener1("myFirstTrigger1"), EverythingMatcher.allTriggers());if(!scheduler.isShutdown()){scheduler.start();}}}

其实我们在阅读listener的接口实现代码时,可以发现在它的实现类中,有一个TriggerListenerSupport的抽象类,即我们也可以继承这个类,只实现其中的部分业务关注的方法

运行这段代码,观察控制台效果,和上面的效果差不多

3、SchedulerListener

SchedulerListener会在Scheduler的生命周期关键事件发生时被调用。与Scheduler有关的事件包括:增加一个job/trigger,删除一个job/trigger,scheduler发生严重错误,关闭scheduler等

参考前面两种的方式,有兴趣的同学可以点击进去看看具体的方法,这里对其中涉及到的几个方法简单解释下

  • 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中的数据被清除时,调用该方法

在接口实现上,可以实现SchedulerListener,也可以继承SchedulerListenerSupport抽象类,下面看具体的代码实现

@Slf4j
public class SchedulerTrigger1 extends SchedulerListenerSupport {@Overridepublic void jobAdded(JobDetail jobDetail) {log.info("1 === 监听到有一个job准备加入进去");}@Overridepublic void jobScheduled(Trigger trigger) {log.info("job准备被调度 jobScheduled");}@Overridepublic void schedulerShutdown() {log.info("job 调度准备停止的时候 schedulerShutdown");}@Overridepublic void schedulerStarted() {log.info("job 调度要开始了 schedulerStarted");}@Overridepublic void schedulerStarting() {super.schedulerStarting();}
}
public class DemoTest3 {private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();public static void main(String[] args) throws Exception {Scheduler scheduler = schedulerFactory.getScheduler();JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("myJob3", "myJobGroup3")//.requestRecovery() // 执行中应用发生故障,需要重新执行.build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myFirstTrigger3", "myFirstTriggerGroup3").startNow().withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?")).build();scheduler.scheduleJob(job, trigger);scheduler.getListenerManager().addSchedulerListener(new SchedulerTrigger1());scheduler.start();Thread.sleep(12000);scheduler.shutdown();}}

运行上面的代码,效果和上面的类似

quartz监听器与springboot的整合

在上一篇中我们讲解了与springboot的整合,这里简单的再走一遍

1、添加依赖

 <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--quartz相关依赖--><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.1</version></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>2.3.1</version></dependency><!--spring boot集成quartz--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

2、两个主要的配置类

@Configuration
public class SchedulerConfig {@Autowiredprivate SpringJobFactory springJobFactory;@Bean(name="SchedulerFactory")public SchedulerFactoryBean schedulerFactoryBean() throws IOException {SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setAutoStartup(true);factory.setStartupDelay(5);//延时5秒启动factory.setQuartzProperties(quartzProperties());factory.setJobFactory(springJobFactory);return factory;}@Beanpublic Properties quartzProperties() throws IOException {PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));propertiesFactoryBean.afterPropertiesSet();return propertiesFactoryBean.getObject();}/** quartz初始化监听器*/@Beanpublic QuartzInitializerListener executorListener() {return new QuartzInitializerListener();}/** 通过SchedulerFactoryBean获取Scheduler的实例*/@Bean(name="Scheduler")public Scheduler scheduler() throws IOException {return schedulerFactoryBean().getScheduler();}}
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
/*** 解决spring bean注入Job的问题*/
@Component
public class SpringJobFactory extends AdaptableJobFactory  {@Autowiredprivate AutowireCapableBeanFactory capableBeanFactory;@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {// 调用父类的方法Object jobInstance = super.createJobInstance(bundle);// 进行注入capableBeanFactory.autowireBean(jobInstance);return jobInstance;}
}

在实际开发中,最好再在资源目录下添加quartz.properties配置文件,控制quartz运行时的相关参数,比如分配线程数等,在之前的篇章中有介绍这里就不再罗列了

3、提供一个任务类,用于初始化调度任务

@Component
public class TaskRunner implements ApplicationRunner {private final static Logger LOGGER = LoggerFactory.getLogger(TaskRunner.class);@Autowired@Qualifier("Scheduler")private Scheduler scheduler;@Overridepublic void run(ApplicationArguments var) throws Exception {LOGGER.info("初始化测试任务");Date date = DateBuilder.futureDate(7, DateBuilder.IntervalUnit.SECOND);//构建job信息JobDetail job = JobBuilder.newJob(QuartzDemo.class).withIdentity("triggerJob", "triggerJobGroup").withDescription("测试任务").build();// 触发时间点CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/3 * * * * ?");Trigger trigger = TriggerBuilder.newTrigger().withIdentity("triggerJob", "triggerJobGroup").startAt(date).withSchedule(cronScheduleBuilder).build();//交由Scheduler安排触发scheduler.scheduleJob(job, trigger);//安排一个监听器scheduler.getListenerManager().addJobListener(new MyJobTriggerListener());if (!scheduler.isShutdown()) {scheduler.start();}}}

启动项目,设置的是7秒之后任务开始调度,观察控制台执行效果,到这里,与springboot的整合也完成

本篇主要讲述了quartz监听器的基本使用以及与springboot的整合,有兴趣的同学可以继续深入研究,本篇到此结束,最后感谢观看!

quartz监听器使用相关推荐

  1. Quartz定时任务学习(九)Quartz监听器

    Quartz 提供了三种类型的监听器:监听 Job 的,监听 Trigger 的,和监听 Scheduler 自已的. 本章解释如何应用每一种类型来更好的管理你的 Quartz 应用,并获悉到什么事件 ...

  2. 项目中使用Quartz集群分享--转载

    原文:http://hot66hot.iteye.com/blog/1726143 在公司分享了Quartz,发布出来,希望大家讨论补充. CRM使用Quartz集群分享  一:CRM对定时任务的依赖 ...

  3. Quartz调用大全

    Quartz调用大全 1.Quartz应用范围广泛,可单独执行也可在spring中嵌入执行. 类似的定时任务在linux下可以用crontab执行 2.实现代码: QuartzTest :主要执行类 ...

  4. 【Quartz】解密properties配置文件中的账号密码

    在配置quartz时,为了保密某些信息(特别是账号密码),通常会使用密文.那么在实际使用这些配置信息时,需要进行解密.本文提供一种解密方法如下: (1)假设在properties文件中加密了账号密码 ...

  5. Servlet过滤器Filter和监听器

    一.Servlet过滤器的概念: *********************************************************************************** ...

  6. 【Quartz】任务调度

    Quartz任务调度 一.Quartz概念 二.Quartz运行环境 三.Quartz设计模式 四.Quartz学习的核心概念 五.Quartz的体系结构 六.Quartz的几个常用API 七.Qua ...

  7. Quartz任务调度——快速入门

    目录 一.Quartz概念 二.Quartz运行环境 三.Quartz设计模式 四.Quartz学习的核心概念 五.Qutarz的体系结构 六.Quartz的几个常用API 七.Quartz的使用 八 ...

  8. Quartz中文文档使用

    Quartz中文使用说明文档,内容相当详细,有需要的码友们可以看看!! 好东西要分享!! 下面是文档的内容目录,附上下载的地址:点击打开链接,下载文档 中文版目录总汇及内容提要 第一章. 企业应用中的 ...

  9. quartz记录job状态

    quartz记录job状态 记录job执行状态 记录执行次数 记录job执行状态 需要记录定时任务每一次的执行情况,并记录执行的次数.因为quartz在1.x版本之后不推荐使用stateful接口,我 ...

最新文章

  1. 编码中统一更该变量的快捷键_流媒体的7种方式使您成为更好的编码器
  2. 8瓶酒一瓶有毒,用人测试。每次测试结果8小时后才会得出,而你只有8个小时的时间。问最少需要(B)人测试?
  3. uva1624knots
  4. Web使用热敏打印小票(IE环境)
  5. 关于逻辑删除标识字段value的设定
  6. 最近做项目的一些关于重构方面的总结
  7. (二)html常用标签
  8. 最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
  9. 俄罗斯方块java分析_[源码和文档分享]基于Java的俄罗斯方块游戏
  10. 一位教授跟我说:线性代数应该这样学
  11. 数据库索引类型介绍及其优缺点、区别、适用场景
  12. div圆角,阴影效果。
  13. 网络地址与直接广播地址有关计算
  14. Greenplum集群扩容总结
  15. D - Sleepy Game
  16. 经纬高坐标系转到东北天坐标系
  17. mysql 存储类型文本最大长度longtext
  18. c语言引用性间接变量,c语言取地址和间接引用
  19. 使用NPOI设置Excel表的单元格背景颜色
  20. 优美图案c语言程序,C语言编程之一个最优美的图案

热门文章

  1. gridview 默认编辑按钮改成图片
  2. Copy Clone
  3. XP下安装SQL2000企业版
  4. 生活等级测试(娱乐性质)
  5. char,nchar,varchar与nvarchar区别
  6. Flask安装首页显示
  7. Core Animation基础
  8. POJ3349 哈希算法
  9. 浅谈SCOM Agent的心跳响应机制
  10. ISA Server 2004 企业 IT 常见应用速查