后端——框架——定时任务——quartz——Trigger

  本篇介绍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,它有三种含义,

  1. 当只有L时,表示当前月的最后一天
  2. 当为num L时,num的范围为1-7,表示星期一到星期日,例如3L,表示最后一个星期的星期三。
  3. 当L-num时,表示当前月的最后几天,例如L-2,表示当月的最后两天。

 

       W,英文全称为WeekDay,表示工作日,即星期一到星期五。

       它表示最近的工作日,格式为num L。例如2W,表示离当月2号最近的一个工作日,总共有以下三种情形

  1. 当月2号为星期六,则会在1号星期五执行
  2. 当月2号为星期日,则会在3号星期一执行
  3. 当月2号为工作日,则会在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的含义相同

  1. 当只有L时,表示当前月的最后一天
  2. 当为num L时,num的范围为1-7,表示星期一到星期日,例如3L,表示最后一个星期的星期三。
  3. 当L-num时,表示当前月的最后几天,例如L-2,表示当月的最后两天。

      注:它的周期是月,不是周

 

#,它的格式为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被否决了。顺序如下:

  1. 调用TriggerListener的triggerFired方法
  2. 调用TriggerListener的vetoJobExecution方法
  3. 调用JobListener的jobExecutionVetoed方法

当Job未被否决时,顺序如下:

  1. 调用TriggerListener的triggerFired方法
  2. 调用TriggerListener的vetoJobExecution方法
  3. 调用JobListener的jobToBeExecuted方法
  4. 调用JobListener的jobWasExecuted方法
  5. 调用TriggerListener的triggerComplete方法。
原文地址:https://www.cnblogs.com/rain144576/p/14749939.html