quartz简介

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/