Quartz Scheduler 开源框架
Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现
Spring 默认的调度框架,Quartz 很容易与 Spring 集成实现灵活可配置的调度功能
名词解释
Trigger 触发器,用于定义任务调度时间规则
Scheduler 任务调度器,Scheduler有两个重要组件:ThreadPool和JobStore
Job 任务 也就是表示被调度的任务.JobDetail是任务的定义,而Job是任务的执行逻辑。在JobDetail里会引用一个Job Class定义
misfire 错过的,指本来应该被执行但实际没有被执行的任务调度
原理
Quartz 任务调度的核心元素是 scheduler, trigger 和 job,其中 trigger 和 job 是任务调度的元数据, scheduler 是实际执行调度的控制器。
trigger 是用于定义调度时间的元素,即按照什么时间规则去执行任务
- SimpleTrigger
- CronTirgger
- DateIntervalTrigger
- NthIncludedDayTrigger
job 用于表示被调度的任务
- 无状态的(stateless)
- 有状态的(stateful)
对于同一个 trigger 来说,有状态的 job 不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行
Job 主要有两种属性:
volatility
durability
其中 volatility 表示任务是否被持久化到数据库存储,而 durability 表示在没有 trigger 关联的时候任务是否被保留。
两者都是在值为 true 的时候任务被持久化或保留。一个 job 可以被多个 trigger 关联,但是一个 trigger 只能关联一个 job。
scheduler
scheduler 由 scheduler 工厂创建:DirectSchedulerFactory 或者 StdSchedulerFactory。
第二种工厂 StdSchedulerFactory 使用较多,因为 DirectSchedulerFactory 使用起来不够方便,需要作许多详细的手工编码设置。
Scheduler 主要有三种:RemoteMBeanScheduler, RemoteScheduler 和 StdScheduler。
本文以最常用的 StdScheduler 为例讲解。
Quartz 核心元素之间的关系如下图所示
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image001.gif
线程视图
在 Quartz 中,有两类线程,Scheduler 调度线程和任务执行线程,其中任务执行线程通常使用一个线程池维护一组线程
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image002.gif
Scheduler 调度线程主要有两个: 执行常规调度的线程,和执行 misfired trigger 的线程。
常规调度线程轮询存储的所有 trigger,如果有需要触发的 trigger,即到达了下一次触发的时间,则从任务执行线程池获取一个空闲线程,执行与该 trigger 关联的任务。
Misfire 线程是扫描所有的 trigger,查看是否有 misfired trigger,如果有的话根据 misfire 的策略分别处理。下图描述了这两个线程的基本流程:
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image003.png
数据存储
Quartz 中的 trigger 和 job 需要存储下来才能被使用。
Quartz 中有两种存储方式:RAMJobStore, JobStoreSupport,
- RAMJobStore 是将 trigger 和 job 存储在内存中,
- JobStoreSupport 是基于 jdbc 将 trigger 和 job 存储到数据库中。
RAMJobStore 的存取速度非常快,但是由于其在系统被停止后所有的数据都会丢失,所以在通常应用中,都是使用 JobStoreSupport。
在 Quartz 中,JobStoreSupport 使用一个驱动代理来操作 trigger 和 job 的数据存储:StdJDBCDelegate。
StdJDBCDelegate 实现了大部分基于标准 JDBC 的功能接口,但是对于各种数据库来说,需要根据其具体实现的特点做某些特殊处理,因此各种数据库需要扩展 StdJDBCDelegate 以实现这些特殊处理。
Quartz 已经自带了一些数据库的扩展实现,可以直接使用,如下图所示:
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image004.png
一个简单实例
Quartz 开发包中有一个 examples 目录,其中有 15 个基本实例。建议读者阅读并实践这些例子。本文这里只列举一个小的实例,介绍基本的开发方法。
准备数据库和 Quartz 用的数据表
本文使用 IBM DB2 数据库:将 jdbc 驱动程序 db2jcc.jar 加入到项目中;
在数据库中创建一个新库 QUARTZDB;
执行 /quartz-1.8.4/docs/dbTables/tables_db2_v8.sql,创建数据表;表建好后如下所示:
图 6. Quartz 数据表
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image006.png
准备配置文件,加入到项目中
图 7. 实例配置文件
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image007.png
通过实现 job 接口定义我们自己的任务类,如下所示:
图 8. 定义任务类
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image008.png
然后,实现任务调度的主程序,如下所示:
本实例中,我们利用 DateIntervalTrigger 实现一个每两分钟执行一次的任务调度。
图 9. 实现主程序
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image009.png
完成后项目结构如下所示:
图 10. 实例项目结构图
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image010.png
运行程序,查看数据库表和运行结果
数据库中,QRTZ_TRIGGERS 表中添加了一条 trigger 记录,如下所示:
图 11. QRTZ_TRIGGERS 表中的记录
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image011.png
QRTZ_JOB_DETAILS 表中添加了一条 job 记录,如下所示:
图 12. QRTZ_JOB_DETAILES 表中的记录
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image012.png
从运行结果来看,任务每两分钟被执行一次:
图 13. 运行结果
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/image013.png
参考文章
https://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/
http://ifeve.com/quartz-tutorial-04-trigger/