简要
Quartz是一个用java编写的job调度框架。
支持数据库,也就是说它可以连接数据库…
支持集群部署,您可以同时在多台机器上部署一个Quartz实例,job数量少时集群部署可以提高可用性…
支持cron表达式(此条是真的)…
尝试使用Quartz
程序员言道:”show me the code”,说得就是在学习任何工具框架之前,最好先跑一跑代码,对框架有第一印象之后再学习。Quartz是个job调度器,没有使用过它的童鞋一时半会儿无法理解调度器,因为job调度是个领域,对该领域没个了解是不行的。
简单地理解,Quartz运行的时候有3部分:Job、触发器和调度器。Job是我们自己写的逻辑代码,比如说发送一封秘密邮件。触发器,配置了Job什么时候执行。调度器,是调度框架的核心,没有它,Job和触发器没有意义。总而言之,言而总之,调度器根据触发器的配置,在特定的条件下『触发』特定的动作,比如我们设定触发器在每天凌晨1点触发我们的发邮件Job,调度器会在每天1点定时启动Job。
下面试调度一个Job
自己写的Job,通常业务逻辑都放在这里:
1 | package com.iloveqyc.service.test.quartz; |
Job调度框架,逻辑相对比较固定,不涉及业务:
1 | package com.iloveqyc.service.test.quartz; |
扫一眼上边的代码,有童鞋会想起Timer或ScheduledThreadPoolExecutor,没错╮(╯_╰)╭,Quartz就是一个类似于定时器的框架,使用Quartz的同学,只需要配置cron表达式和Job逻辑,不用亲自编写定时器。
Job & JobDetail
在Quartz中,Job用于存放业务的逻辑,回顾下我们是如何编写Job的:
1 | public class QycJob implements Job { |
可以看到,Job在运行的时候,Quartz向它传入JobExecutionContext,运行上下文,里边存放着Job运行时的信息,比如Job的名称,Job的执行情况等。
再回顾下我们怎么运行一个Job:
1 | // 新建一个任务 |
我们把Job放入JobDetail,再把JobDetail传给调度器,相当于把Job封装了一层,看下官方源码声明:
1 | Quartz does not store an actual instance of a <code>Job</code> class, but |
为什么这么做呢?Job本身仅会有业务逻辑,不存其它信息。如果在Job运行时,我们想给Job传入某些变量值,可以借助JobDetail。
JobDetail内部有JobDataMap,调度器实例化一个Job,调用Job的execute方法前,可以往JobDataMap中塞值。这样一来,Job在execute的时候,可以从JobExecutionContext里拿到JobDataMap,进而拿到特定的变量值。
Trigger
利用好触发器,你可以让Job在你希望的时间点执行。每个Job可以拥有多个触发器,一个触发器只能绑定到一个Job。
调度器在调度的时候,会扫描所有的触发器,分别执行它们。针对每个Job,Quartz会用线程池里的线程执行,如果多个触发器都在同一时间点触发,而Quartz内部没有足够多的线程跑触发器对应的Job,那么会随机或是优先选择某些Job。
如果你希望你的Job间隔特定的时间执行,可以用SimpleTrigger;如果你的Job没有固定的间隔时间,可以用CronTrigger,配置上cron表达式。
触发失败
在触发失败时,Quartz有多种补偿策略,比如放弃触发,重新触发等。
调度器
调度器有2种线程,一种用来执行Job,一种用来轮询扫描所有触发器,若符合条件则进行触发。
Listener
Quartz为了加强定制性,给触发器、Job、调度器都添加了监听器的支持。
触发器监听器
当触发器发生以下事件时,会被触发器监听器TriggerListener识别到:被触发、触发失败、触发完成(下一步将是Job的运行)
你可以自己实现TriggerListener接口,在相应事件发生时执行某些操作,比如记日志,比如发邮件等。
Job监听器
当Job即将开始执行(此时触发器已经触发完成)、或是执行完毕时,相应事件可以被JobListener识别到。
调度器监听器
SchedulerListener识别的事件有:添加/移除用户的Job/触发器监听器、发生错误、调度器被shutdown。
特性
JobStores
这个东西不对Quartz的使用者开放,仅为Quartz幕后使用,它的作用是存储Quartz运行过程中所有的数据。
RamJobStore把数据存储在内存中;JDBCJobStore把数据存储在数据库里,支持多种数据库(涉及到数据库,就会有事务,Quartz自身有事务管理器,当然,你也可以让别的框架来管理事务,比如spring)。
线程池
Quartz内部是有线程池的,用来运行Job,一般情况下,5个线程就够了。
集群
Quartz支持集群配置,设置“org.quartz.jobStore.isClustered”参数为true可以开启,不过它对集群内机器的时间同步有比较高的要求,误差不超过1秒。
Quartz的集群没有中心管理节点,机器与机器之间根据数据库里的数据来判断其它机器的存在。
每个机器上的调度器定时到数据库中签到,刷新自己的存活时间。如果某个调度器很久不签到,其它调度器就会默认该调度器已经挂掉,接过它手中的Job继续运行(如果Job配置了恢复属性的话,如果Job没配置该属性,那么只能等待下一次的触发了)。