本篇介绍Trigger, 它是顶层接口,Trigger的类结构如下:
MutableTrigger:是状态可变的触发器,不单独使用,所有Trigger都继承此接口。
CoreTrigger:存在额外属性的触发器,只有一个方法hasAddtionalProperties。不单独使用,所有Trigger都继承此接口。
CalendarIntervalTrigger:根据日期,间隔触发,日期中只包含年,月,日,间隔的单位也只有年,月,日。
DailyTimeIntervalTrigger: 根据日期,间隔触发,日期中只包含时,分,秒,间隔的单位也只有时,分,秒。
SimpleTrigger:根据日期,间隔触发,日期中包含年,月,日,时,分,秒。
CronTrigger:根据Cron表达式触发。
经常使用的只有两种,SimpleTrigger和CronTrigger。
除上述对象之外,Trigger相关的对象与Job相关的对象相似,也有TriggerBuilder,TriggerKey,TriggerDataMap, TriggerListener。
1、属性
@SuppressWarnings("unchecked") public T build() { if(scheduleBuilder == null) scheduleBuilder = SimpleScheduleBuilder.simpleSchedule(); MutableTrigger trig = scheduleBuilder.build(); trig.setCalendarName(calendarName); trig.setDescription(description); trig.setStartTime(startTime); trig.setEndTime(endTime); if(key == null) key = new TriggerKey(Key.createUniqueName(null), null); trig.setKey(key); if(jobKey != null) trig.setJobKey(jobKey); trig.setPriority(priority); if(!jobDataMap.isEmpty()) trig.setJobDataMap(jobDataMap); return (T) trig; }
calendarName:Calendar对象的唯一标识。排除特定时间,参考Calendar对象。
description:Trigger的描述信息。
startTime:Trigger触发的开始时间。它不是任务真正的开始时间。
endTime:Trigger触发的结束时间。它不是任务真正的结束时间。
triggerKey:Trigger的唯一标识,名称和组。
triggerDataMap:与JobDataMap基本相同。
priority:Trigger的优先级。
2、 SimpleTrigger
SimpleTrigger的知识点有两个,设置SimpleTrigger的属性,它的Mis_fire策略。
2.1 设置属性
设置属性是通过调用TriggerBuilder的相关方法。
TriggerKey:调用withIdentity方法,第一个参数表示name,第二个参数表示group。
startTime:调用startAt方法,参数为date。也可以调用startNow。
间隔:调用withScheduler方法,参数为ScheduleBuilder,它有实现类XXScheduleBuilder,每个实现类中都有withIntervalXXX,后面的XXX代表的是间隔的时间单位,方法的参数代表间隔的时间值。
重复次数:调用withRepeatCount方法,参数为其值。调用repeatForever无限重复。
endTime:调用endAt方法。
关联Job:调用forJob方法。
2.2 MisFire
当SimpleTrigger未被正常触发之后,有以下六种策略。
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
/** * Instructs the <code>{@link Scheduler}</code> that the * <code>Trigger</code> will never be evaluated for a misfire situation, * and that the scheduler will simply try to fire it as soon as it can, * and then update the Trigger as if it had fired at the proper time. * * <p>NOTE: if a trigger uses this instruction, and it has missed * several of its scheduled firings, then several rapid firings may occur * as the trigger attempt to catch back up to where it would have been. * For example, a SimpleTrigger that fires every 15 seconds which has * misfired for 5 minutes will fire 20 times once it gets the chance to * fire.</p> */ public static final int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;
快速的执行任务(重复次数相同),忽略开始时间,间隔,结束时间。不能用于无限重复的触发器。
MISFIRE_INSTRUCTION_FIRE_NOW
/** * <p> * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire * situation, the <code>{@link SimpleTrigger}</code> wants to be fired * now by <code>Scheduler</code>. * </p> * * <p> * <i>NOTE:</i> This instruction should typically only be used for * 'one-shot' (non-repeating) Triggers. If it is used on a trigger with a * repeat count > 0 then it is equivalent to the instruction <code>{@link #MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT} * </code>. * </p> */
在now执行一次,之后将now作为开始时间,间隔不变,重复次数为剩余的重复次数
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
/** * <p> * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire * situation, the <code>{@link SimpleTrigger}</code> wants to be * re-scheduled to 'now' (even if the associated <code>{@link Calendar}</code> * excludes 'now') with the repeat count left as-is. This does obey the * <code>Trigger</code> end-time however, so if 'now' is after the * end-time the <code>Trigger</code> will not fire again. * </p> * * <p> * <i>NOTE:</i> Use of this instruction causes the trigger to 'forget' * the start-time and repeat-count that it was originally setup with (this * is only an issue if you for some reason wanted to be able to tell what * the original values were at some later time). * </p> */ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT = 2;
将now作为开始时间,间隔不变,重复次数为剩余的重复次数,它受结束时间的约束,当到达结束时间时,任务不会在执行,当now大于结束时间时,任务不会执行
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
/** * <p> * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire * situation, the <code>{@link SimpleTrigger}</code> wants to be * re-scheduled to 'now' (even if the associated <code>{@link Calendar}</code> * excludes 'now') with the repeat count set to what it would be, if it had * not missed any firings. This does obey the <code>Trigger</code> end-time * however, so if 'now' is after the end-time the <code>Trigger</code> will * not fire again. * </p> * * <p> * <i>NOTE:</i> Use of this instruction causes the trigger to 'forget' * the start-time and repeat-count that it was originally setup with. * Instead, the repeat count on the trigger will be changed to whatever * the remaining repeat count is (this is only an issue if you for some * reason wanted to be able to tell what the original values were at some * later time). * </p> * * <p> * <i>NOTE:</i> This instruction could cause the <code>Trigger</code> * to go to the 'COMPLETE' state after firing 'now', if all the * repeat-fire-times where missed. * </p> */ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT = 3;
将now作为开始时间,间隔不变,重复次数为剩余的重复次数,与EXISTING的区别在于它不受结束时间的约束
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
/** * <p> * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire * situation, the <code>{@link SimpleTrigger}</code> wants to be * re-scheduled to the next scheduled time after 'now' - taking into * account any associated <code>{@link Calendar}</code>, and with the * repeat count set to what it would be, if it had not missed any firings. * </p> * * <p> * <i>NOTE/WARNING:</i> This instruction could cause the <code>Trigger</code> * to go directly to the 'COMPLETE' state if all fire-times where missed. * </p> */ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT = 4;
与NOW的区别是它不改变开始时间,根据原始任务的开始时间,间隔计算下次的触发时间。不受结束时间的约束
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
/** * <p> * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire * situation, the <code>{@link SimpleTrigger}</code> wants to be * re-scheduled to the next scheduled time after 'now' - taking into * account any associated <code>{@link Calendar}</code>, and with the * repeat count left unchanged. * </p> * * <p> * <i>NOTE/WARNING:</i> This instruction could cause the <code>Trigger</code> * to go directly to the 'COMPLETE' state if the end-time of the trigger * has arrived. * </p> */ public static final int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT = 5;
与NOW的区别是它不改变开始时间,与REMAINING的区别是它受到时间状态的约束
3、CronTrigger
CronTrigger的知识点有三个,设置属性,Cron表达式,MisFire策略。
3.1 设置属性
TriggerKey:调用withIdentity方法,第一个参数为名称,第二个参数为组。
Cron表达式:调用withScheduler方法,参数为ScheduleBuilder,CronScheduleBuilder为其实现类之一。调用CronScheduleBuilder的cronSchedule方法,参数为cron表达式。
timezone:调用withScheduler方法,参数为ScheduleBuilder,CronScheduleBuilder为其实现类之一。调用CronScheduleBuilder的inTimeZone方法,参数为TimeZone对象。
3.2 Cron表达式
Cron表达式的格式有七部分组成。分别是:
秒 分钟 小时 天(某月的一天) 月 周 年
下面具体分析每个部分的格式
3.2.1 秒
格式 |
num ,— * / |
允许值 |
0-59 |
是否必填 |
是 |
示例 |
单个数值形式,例如0 表示在第0秒执行 |
多个数值形式(逗号),例如0,15,20 表示在第0秒,15秒,20秒执行 |
|
数值范围形式(横杠),例如0-15 表示在0-15秒之间每一秒都执行一次 |
|
数值递增形式(斜杠),例如3/15 其中3表示初始值,15表示递增值,表示在3,18, 43 ,58秒执行 |
|
任意值(通配符),例如 * 表示每秒执行一次,这个通常不适用 |
3.2.2 分钟
与秒的格式基本相同
格式 |
num ,— * / |
允许值 |
0-59 |
是否必填 |
是 |
示例 |
单个数值形式,例如0 表示在第0分钟执行 |
多个数值形式(逗号),例如0,15,20 表示在第0分,15分,20分执行 |
|
数值范围形式(横杠),例如0-15 表示在0-15分之间每一分都执行一次 |
|
数值递增形式(斜杠),例如3/15 其中3表示初始值,15表示递增值,表示在3,18, 43 ,58分执行 |
|
任意值(通配符),例如 * 表示每分执行一次 |
3.2.3 小时
与秒,分钟的格式基本相同
格式 |
num ,— * / |
允许值 |
0-59 |
是否必填 |
是 |
示例 |
单个数值形式,例如0 表示在第0小时执行 |
多个数值形式(逗号),例如0,15,20 表示在第0时,15时,20时执行 |
|
数值范围形式(横杠),例如0-15 表示在0-15时之间每一小时执行一次 |
|
数值递增形式(斜杠),例如3/15 其中3表示初始值,15表示递增值,表示在3,18, 43 ,58小时执行 |
|
任意值(通配符),例如 * 表示每小时执行一次 |
3.2.4 天
表示当前月的某一天
格式 |
num ,— * / ? L W |
允许值 |
1-31 |
是否必填 |
是 |
示例 |
单个数值形式,例如1 表示在每月的第一天执行 |
|
多个数值形式(逗号),例如1,15,20 表示在第1号,15号,20号执行 |
|
数值范围形式(横杠),例如0-15 表示在0-15时之间每一天执行一次 |
|
数值递增形式(斜杠),例如3/15 其中3表示初始值,15表示递增值,表示在3,18,号执行 |
|
任意值(通配符),例如 * 表示每天执行一次 |
|
无特定值(问号),它与通配符的区别在于前者表示任意值,本身为当前字段设置了规则,而无特定值的含义是指本身没有为当前字段设置任何规则,而是由其他字段指定规则,与day-of-month存在交集的就是day-of-week字段。问号的意思是由另外一方指定规则。 |
|
L,它有三种含义,
|
|
W,英文全称为WeekDay,表示工作日,即星期一到星期五。 它表示最近的工作日,格式为num L。例如2W,表示离当月2号最近的一个工作日,总共有以下三种情形
不论是哪种形式,不会跨月,例如1号为星期六,只会在3号星期一执行 |
3.2.5 月
格式基本与小时,分,秒相同,区别在于月有数值和缩写两种形式。
格式 |
num或abbr ,— * / |
允许值 |
1-12 |
是否必填 |
是 |
示例 |
单个数值/缩写形式,例如1表示在第1月执行,JAN的含义相同 |
多个数值/缩写形式(逗号),例如1,3,5 表示在第1,3,5月执行 |
|
数值/缩写范围形式(横杠),例如1-13 表示在1-3月之间执行 |
|
数值/缩写递增形式(斜杠),例如1/5 其中1表示初始值,5表示递增值,表示在1,6, 11月执行 |
|
任意值(通配符),例如 * 表示每月执行一次 |
3.2.6 周
格式 |
num ,— * / ? L # |
允许值 |
1-7 |
是否必填 |
是 |
示例 |
单个数值/缩写形式,例如1 表示在星期一执行 |
|
多个数值/缩写形式(逗号),例如1,4 表示在周一,周四执行 |
|
数值/缩写范围形式(横杠),例如1-3 表示在周一,周二,周三执行 |
|
数值/缩写递增形式(斜杠),例如3/2 其中3表示初始值,2表示递增值,表示在周三,周六执行 |
|
任意值(通配符),例如 * 表示每天执行一次 |
|
无特定值(问号),它与通配符的区别在于前者表示任意值,本身为当前字段设置了规则,而无特定值的含义是指本身没有为当前字段设置任何规则,而是由其他字段指定规则,与day-of-week存在交集的就是day-of-month字段。问号的意思是由另外一方指定规则。 |
|
L,它有三种含义,与day-of-month的含义相同
注:它的周期是月,不是周 |
|
#,它的格式为num1 # num2,num1的值为1-7,表示周一到周日,num2的值为当月的第几周,一般不会超过5。例如 2#3,表示当月的第三周的周二。当计算得出无实际日期时,不会出错但也无任何含义,例如5#6,当月第六周的周五无任何含义。 |
3.2.7 年
格式 |
num ,— * / |
允许值 |
Empty,1970-2099 |
是否必填 |
否 |
示例 |
单个数值形式,例如2020 表示在2020年执行 |
多个数值形式(逗号),例如2020,2025 表示在2020年和2025年执行 |
|
数值范围形式(横杠),例如2020-2025 表示在2020-2025之间执行 |
|
数值递增形式(斜杠),例如2020/10 其中2020表示初始值,10表示递增值,表示在2020,2030, 2040等年份执行 |
|
任意值(通配符),例如 * 表示每年执行 |
在使用Cron表达式时,需要注意间隔的时间单位会根据表达式推算出来,例如0/15设置在秒字段,会导致一分钟执行四次任务。
3.3 MisFire
当CronTrigger未被正常触发之后,有以下三种策略。
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
/** * Instructs the <code>{@link Scheduler}</code> that the * <code>Trigger</code> will never be evaluated for a misfire situation, * and that the scheduler will simply try to fire it as soon as it can, * and then update the Trigger as if it had fired at the proper time. * * <p>NOTE: if a trigger uses this instruction, and it has missed * several of its scheduled firings, then several rapid firings may occur * as the trigger attempt to catch back up to where it would have been. * For example, a SimpleTrigger that fires every 15 seconds which has * misfired for 5 minutes will fire 20 times once it gets the chance to * fire.</p> */ public static final int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;
短时间内快速的执行任务。与SimpleTrigger的第一种策略相同。不适用于无限重复的任务
MISFIRE_INSTRUCTION_DO_NOTHING
/** * <p> * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire * situation, the <code>{@link CronTrigger}</code> wants to have it's * next-fire-time updated to the next time in the schedule after the * current time (taking into account any associated <code>{@link Calendar}</code>, * but it does not want to be fired now. * </p> */ public static final int MISFIRE_INSTRUCTION_DO_NOTHING = 2;
未被触发的被忽略,之后的计算下次执行时间。
MISFIRE_INSTRUCTION_FIRE_NOW
/** * <p> * Instructs the <code>{@link Scheduler}</code> that upon a mis-fire * situation, the <code>{@link CronTrigger}</code> wants to be fired now * by <code>Scheduler</code>. * </p> */ public static final int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
在now执行一次,之后计算下次的执行时间,等价于MISFIRE_INSTRUCTION_SMART_POLICY。
4、TriggerListener
除TriggerListener之外,TriggerBuilder, TriggerKey, TriggerDataMap与Job中的相关对象含义基本相同,不再重复。
TriggerListener的源码如下:
public interface TriggerListener { public String getName(); public void triggerFired(Trigger trigger, JobExecutionContext context); public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context); public void triggerMisfired(Trigger trigger); public void triggerComplete(Trigger trigger, JobExecutionContext context, int triggerInstructionCode); }
getName:返回Trigger的名称
triggerFired:被触发时执行
vetoJobExectution:对Job进行vote,返回true,否决Job,Job将不会再执行。默认返回false。
triggerMisFired:未被正常触发时执行
triggerComplete:触发完成时执行
Listener的触发顺序分两种情况:
当Job被否决了。顺序如下:
- 调用TriggerListener的triggerFired方法
- 调用TriggerListener的vetoJobExecution方法
- 调用JobListener的jobExecutionVetoed方法
当Job未被否决时,顺序如下:
- 调用TriggerListener的triggerFired方法
- 调用TriggerListener的vetoJobExecution方法
- 调用JobListener的jobToBeExecuted方法
- 调用JobListener的jobWasExecuted方法
- 调用TriggerListener的triggerComplete方法。