任务调度之Quartz(二):Quartz体系结构
1、Quartz 体系结构
由上一篇的Quartz基本使用可以发现,Quartz 主要包含一下几种角色:
1)Job:也可以认为是JobDtetail,表示具体的调度任务
2)Trigger:触发器,用于定义任务Job出发执行的规律
3)Scheduler:调度器,用于将 JobDetail 和 Trigger绑定,并注册到容器中
4)Listener:监听器,Quartz 中提供了3种监听器,即 JobListener、TriggerListener、
SchedulerListener分别用来监听 Job、Trigger、Scheduler 的执行情况
5)Jobstore:用来存储任务和触发器相关的信息
如下图所示:
注意:
由上图可以发现,其中JobDetail是1对多(1:N)的关系,即一个JobDetail可以
去绑定多个触发器Trigger
2、JobDetail
由Quartz基本使用笔记可以知道,在 Quartz 中Job需要通过JobBuilder 包装成JobDetail
后才能被使用,具体用法请参考“Quartz基本使用”。
3、Trigger
触发器 Trigger 通过Trigger Builder来构建,用于定义任务Job出发执行的规律。
Trigger 在Quartz 中有4种子接口,分别是:
1)SimpleTrigger:简单触发器,固定时刻或时间间隔触发,单位毫秒
可以定义固定时刻或者固定时间间隔的调度规则(精确到毫秒)。
例如:每天 9 点钟运行;每隔 30 分钟运行一次。
2)CalendarIntervalTrigge:基于日历的触发器,单位秒,比简单触发器更多时间单位,
支持非固定时间的触发,例如一 年可能 365/366,一个月可能 28/29/30/31
好处是不需要去计算时间间隔,比如 1 个小时等于多少毫秒。
每年的月数和每个月的天数不是固定的,这种情况也适用。
3)DailyTimeIntervalTrigger:基于日期的触发器,每天某个时间段触发,即每天的某
个时间段内,以一定的时间间隔执行任务。
例如:每天早上 9 点到晚上 9 点,每隔半个小时执行一次,并且只在
周一到周六执行。
4)CronTrigger:基于 Cron 表达式的触发器,可以定义基于 Cron 表达式的调度规则,
是最常用的触发器类型。
3.1、Cron 表达式
是一种用于指定定期执行任务的时间规则的字符串表达式。它由6或7个字段组成,
每个字段代表不同的时间单位,包括秒、分、时、日、月、星期和年。
Cron表达式通常以空格分隔这些字段,格式如下:
秒 分 时 日 月 星期 年
位置 | 时间域 | 特殊值 | |
---|---|---|---|
1 | 秒 | 0-59 | , - * / |
2 | 分钟 | 0-59 | , - * / |
3 | 小时 | 0-23 | , - * / |
4 | 日期 | 1-31 | , - * ? / L W C |
5 | 月份 | 1-12 | , - * / |
6 | 星期 | 1-7 | , - * ? / L W C |
7 | 年份(可选) | 1-31 | , - * / |
Cron 表达式特殊值含义:
1)星号(*):可用在所有字段中,表示对应时间域的每一个时刻,
例如,在分钟字段时,表示“每分钟”;
2)问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,
相当于点(.)位符;
3)减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从 10 到 12 点,
即 10,11,12;
4)斜杠(/):x/y 表达一个等步长序列,x 为起始值,y 为增量步长值。
如:在分钟字段中使用 0/15,则表示为 0,15,30 和 45 秒,而 5/15 在分钟字段
中表示 5,20,35,50,你也可以使用*/y,它等同于 0/y;
5)L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不
同。L 在日期字段中,表示 这个月份的最后一天,如一月的 31 号,非闰年二月
的 28 号;如果 L 用在星期中,则表示星期六,等同于 7。但是,如果 L 出现在
星期字段里,而且在前面有一个数值 X,则表示“这个月的最后 X 天”,
例如:6L 表示该月的最后星期五;
6)W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。
例如 :15W 表示离该月 15号最近的工作日,如果该月 15 号是星期六,则匹配 14
号星期五;如果 15 日是星期日,则匹配 16 号星期一;如果 15号是星期二,
那结果就是 15 号星期二。但必须注意关联的匹配日期不能够跨月,如你指定
1W,如果 1 号是星期六,结果匹配的是 3 号星期一,而非上个月最后的那
天。W 字符串只能指定单一日期,而不能指定日期范围;
7)LW 组合:在日期字段可以组合使用 LW,它的意思是当月的最后一个工作日;
8)井号(#):该字符只能在星期字段中使用,表示当月某个工作日。
如 :6#3 表示当月的第三个星期五(6 表示星期五,#3 表示当前的第三个),而
4#5 表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;
9)C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联
的日期,如果日期没有被关联,则相当于日历中所有日期。
例如: 5C 在日期字段中就相当于日历 5 日以后的第一天。1C 在星期字段中相当于
星期日后的第一天。
注意:
Cron 表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。
4、Scheduler
调度器Scheduler 是Quartz的指挥官,由StdSchedulerFactory产生。它是单例的。
Scheduler默认是实现类是StdScheduler,里面包含了一个QuartzScheduler,
QuartzScheduler里面又包含了一个QuartzSchedulerThread。
Scheduler中的方法主要分为三大类:
1)操作调度器本身,例如调度器的启动start()、调度器的关闭shutdown()。
2)操作Trigger,例如pauseTriggers()、resumeTrigger()。
3)操作Job,例如scheduleJob()、unscheduleJob()、rescheduleJob()
Scheduler 方法非常多,这里就不一一列举了。
5、Listener
Quartz 中提供了3种监听器,即 JobListener、TriggerListener、SchedulerListener分
别用来监听 Job、Trigger 和 Scheduler 的运行情况。
5.1、JobListener
JobListener 主要用于监听 JobDetail(即Job) 在运行过程中是否有关键事件发生;
这些关键事件包括:JobDetail是否被Trigger否决、JobDetail 是否执行完成等。
JobListener 主要方法包括:
1)getName():返回JobListener 的名称
2)jobToBeExecuted():Scheduler 在 JobDetail 将要被执行时调用这个方法
3)jobExecutionVetoed():Scheduler 在 JobDetail 即将被执行,但又被 TriggerListener
否决了时调用这个方法
4)jobWasExecuted():Scheduler 在 JobDetail 被执行之后调用这个方法
5.2、TriggerListener
TriggerListener 主要被用来监听触发器Trigger是否被触发,及触发后Job的execute 方法
是否被执行。
TriggerListener 常用方法如下:
1)getName():返回监听器的名称
2)triggerFired():Trigger 被触发,Job 上的 execute() 方法将要被执行时,Scheduler
就调用这个方法
3)vetoJobExecution():在 Trigger 触发后,Job 将要被执行时由 Scheduler 调用这个
方法。TriggerListener 给了一个选择去否决 Job 的执行。假如这个方法返回
true,这个 Job 将不会为此次 Trigger 触发而得到执行
4)triggerMisfired():Trigger 错过触发时调用
5)triggerComplete():Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个
方法
5.3、SchedulerListener
SchedulerListener主要用于监控 Scheduler 的生命周期中是否有关键事件发生,
当 Scheduler 有关键事件发生时 SchedulerListener 会被调用
与Scheduler有关的事件包括:增加一个job/trigger,删除一个job/trigger,scheduler
运行时发送错误,关闭scheduler等。
6、Jobstore
Jobstore 主要用来存储任务和触发器相关的信息,例如所有任务的名称、数量、状态等等。
Quartz中有两种存储任务的方式,一种在在内存,一种是在数据库。
6.1、RAMJobstore
Quartz默认的JobStore是RAMJobstore,也就是把任务和触发器信息运行的信息存储在内
存中,用到了HashMap、TreeSet、HashSet等等数据结构。
如果程序崩溃或重启,所有存储在内存中的数据都会丢失。所以我们需要把这些数据持久化
到磁盘或保存到数据库中。
6.2、JDBCJobStore
JDBCJobStore可以通过JDBC接口,将任务运行数据保存在数据库中。
JDBC的实现方式有两种,JobStoreSupport类的两个子类:
JobStoreTX:在独立的程序中使用,自己管理事务,不参与外部事务。
JobStoreCMT:(Container Managed Transactions (CMT),如果需要容器管理事务时
,使用它。
如下图所示:
注意:
使用JDBCJobSotre时,需要配置数据库信息并创建对应的表结构
在quartz-jobsb包下,路径 src\org\quartz\impl\jdbcjobstore 下,Quartz
提供了各种数据库的sql文件,直接拿来执行就行了,如下图所示:
数据库配置如下:
在配置文件 quartz.properties 中配置 数据源信息,如下所示:
/**
JobStore持久化配置:将Quartz的数据保存到数据库中的配置
*/
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 使用quartz.properties,不使用默认配置
org.quartz.jobStore.useProperties:true
#数据库中quartz表的表名前缀
org.quartz.jobStore.tablePrefix:QRTZ_
org.quartz.jobStore.dataSource:myDS
#配置数据源
org.quartz.dataSource.myDS.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL:jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf8
org.quartz.dataSource.myDS.user:root
org.quartz.dataSource.myDS.password:123456
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
quartz 需要的表名称与作用如下:
表名 | 作用 |
---|---|
QRTZ_BLOB_TRIGGERS | Trigger作为Blob类型存储 |
QRTZ_CALENDARS | 存储Quartz的Calendar信息 |
QRTZ_CRON_TRIGGERS | 存储CronTrigger,包括Cron表达式和时区信息 |
QRTZ_FIRED_TRIGGERS | 存储与已触发的Trigger相关的状态信息,以及相关Job的执行信息 |
QRTZ_JOB_DETAILS | 存储每一个已配置的Job的详细信息 |
QRTZ_LOCKS | 存储程序的悲观锁的信息 |
QRTZ_PAUSED_TRIGGER_GRPS | 存储已暂停的Trigger组的信息 |
QRTZ_SCHEDULER_STATE | 存储少量的有关Scheduler的状态信息,和别的Scheduler实例 |
QRTZ_SIMPLE_TRIGGERS | 存储SimpleTrigger的信息,包括重复次数、间隔、以及已触的次数 |
QRTZ_SIMPROP_TRIGGERS | 存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器 |
QRTZ_TRIGGERS | 存储已配置的Trigger的信息 |