首页 > 代码库 > Quartz使用(3) - Quartz核心接口Trigger

Quartz使用(3) - Quartz核心接口Trigger

Trigger最常用的有两种SimpleTrigger和CronTrigger,首先介绍Trigger的一些基础的信息,然后会详细描述这两种Trigger。

1. 通用Trigger属性

quartz中所有的触发器Trigger都有一些共有属性,如TriggerKey,startTime等,这些属性可以使用TriggerBuilder进行设置。常用的属性举例如下:

(1) triggerKey:触发器的标识,由名称与分组唯一指定,便于调度器调用与查找。

(2) jobKey: 当触发器被触发时,标识哪一个任务Job应该被执行。

(3) startTime: 表示触发器第一次开始触发的时间。

(4) endTime: 表示触发器终止触发的时间。

2. 优先级

当存在多个触发器时,quartz可能没有足够的资源立即触发所有配置为同一时间触发的triggers,因此可以设置每个Trigger的优先级。默认的优先级为5,可取任意的整型值,包括正数或负数。注意优先级仅用于所有相同时间触发的triggers

3. 未启动指令"Misfire  Instructions"

Trigger未触发一般产生于调度器被关闭,或线程池不足时。不同的Trigger类型有不同的未启动指令。默认的,他们会使用"smart policy"指定。这些指令的使用场景在于,当scheduler开启时,它将搜索所有未启动的持久化的触发器,然后基于触发器各自配置"未启动指令"来更新触发器。未启动指令用于当trigger未正常触发时,是否恢复执行的场景。

4. Calendars

与Trigger关联的Calendar对象,用于在指定的时间内不触发trigger,例如你有一个任务每天执行一次,但你不希望在节假日执行时,Calendar此时派上用场。注意此Calendar为quartz自身的定义接口,而非Java自带的Calendar。

Calendar需要在Scheduler定义过程中,通过scheduler.addCalendar()进行初始化和注册。

示例:

技术分享
import static org.quartz.JobBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
Trigger t = newTrigger()
    .withIdentity("myTrigger")
    .forJob("myJob")
    .withSchedule(dailyAtHourAndMinute(9, 30)) // execute job daily at 9:30
    .modifiedByCalendar("myHolidays") // but not on holidays
    .build();

// .. schedule job with trigger

Trigger t2 = newTrigger()
    .withIdentity("myTrigger2")
    .forJob("myJob2")
    .withSchedule(dailyAtHourAndMinute(11, 30)) // execute job daily at 11:30
    .modifiedByCalendar("myHolidays") // but not on holidays
    .build();

// .. schedule job with trigger2
View Code

 5. SimpleTrigger

 当需要在规定时间执行一次或在规定的时间段以一定的时间间隔重复触发执行Job时,SimpleTrigger就可以满足。

SimpleTrigger的属性有:开始时间、结束时间、重复次数和重复的时间间隔。重复次数属性的值可以为0、正整数、或常量 SimpleTrigger.REPEAT_INDEFINITELY,重复的时间间隔属性值必须为0或长整型的正整数,以毫秒作为时间单位,当重复的时间间隔为0时,意味着与Trigger同时触发执行。如果有指定结束时间属性值,则结束时间属性优先于重复次数属性,这样的好处在于:当我们需要创建一个每间隔10秒钟触发一次直到指定的结束时间的 Trigger,而无需去计算从开始到结束的所重复的次数,我们只需简单的指定结束时间和使用REPEAT_INDEFINITELY作为重复次数的属性 值即可。

 示例:

(1) 创建在特定时间触发,非重复的Trigger

技术分享
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.DateBuilder.*:
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger1", "group1")
    .startAt(myStartTime) // some Date
    .forJob("job1", "group1") // identify job with name, group strings
    .build();
View Code

(2) 创建在特定时间触发,重复间隔为10次,重复执行10次的Trigger

技术分享
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.DateBuilder.*:
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .startAt(myTimeToStartFiring)  // if a start time is not given (if this line were omitted), "now" is implied
    .withSchedule(simpleSchedule()
        .withIntervalInSeconds(10)
        .withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
    .forJob(myJob) // identify job with handle to its JobDetail itself                   
    .build();
View Code

(3) 创建5分钟后执行,且触发一次的Trigger

技术分享
trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger5", "group1")
    .startAt(futureDate(5, IntervalUnit.MINUTE)) // use DateBuilder to create a date in the future
    .forJob(myJobKey) // identify job with its JobKey
    .build();
View Code

(4) 创建立即执行,且重复间隔为5分钟,到22点结束的Trigger

技术分享
trigger = newTrigger()
    .withIdentity("trigger7", "group1")
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever())
    .endAt(dateOf(22, 0, 0))
    .build();
View Code

(5) 创建在下一小时触发,且每2小时执行重复执行的Trigger

技术分享
trigger = newTrigger()
    .withIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
    .startAt(evenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
    .withSchedule(simpleSchedule()
        .withIntervalInHours(2)
        .repeatForever())
    // note that in this example, ‘forJob(..)‘ is not called
    //  - which is valid if the trigger is passed to the scheduler along with the job  
    .build();

    scheduler.scheduleJob(trigger, job);
View Code

SimpleTrigger的未启动指令包含如下:

MISFIRE_INSTRUCTION_SMART_POLICY
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY MISFIRE_INSTRUCTION_FIRE_NOW MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

构件SimpleTrigger的时候,可以指定Trigger的未启动指令:

技术分享
trigger = newTrigger()
    .withIdentity("trigger7", "group1")
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever()
        .withMisfireHandlingInstructionNextWithExistingCount())
    .build();
View Code

 

6. CronTrigger 

6.1 cron表达式

CronTrigger 支持比SimpleTrigger更具体、更复杂的调度。基于cron表达式,CronTrigger支持类似日历的重复间隔,而非单一的时间间隔。

序号 说明 是否必填 允许填写的值 允许的通配符
1 0-59 , - * /
2 0-59 , - * /
3 小时 0-23 , - * /
4 1-31  , - * ? / L W
5 1-12或JAN-DEC , - * /
6 1-7或SUN-SAT , - * ? / L #
7 空或1999-2017 , - * /

通配符的说明:

(1) 反斜线(/)字符表示增量值。例如,在秒字段中“5/15”代表从第 5 秒开始,每 15 秒一次。

(2) 星号(*)字符是通配字符,表示该字段可以接受任何可能的值,例如:在分的字段上设置 "*",表示每一分钟都会触发。

(3) 问号(?)问号表示这个字段不包含具体值。如果指定月内日期,可以在月内日期字段中插入“?”,表示周内日期值无关紧要。

(4) -  表示区间,例如 在小时上设置 "10-12",表示 10,11,12点都会触发。

(5) 逗号(, ) 表示指定多个值,例如在周字段上设置 "MON,WED,FRI" 表示周一,周三和周五触发。

(6) 井号(#)字符为给定月份指定具体的工作日实例。把“MON#2”放在周内日期字段中,表示把任务安排在当月的第二个星期一。

(7) L 表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六,相当于"7"或"SAT"。如果在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示“本月最后一个星期五"。

(8) W 表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 "1W",它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,"W"前只能设置具体的数字,不允许区间"-")。

注:‘L‘和 ‘W‘可以组合使用。如果在日字段上设置"LW",则表示在本月的最后一个工作日触发。

cron表达式的举例如下:

技术分享
0 10 * * * ?--------------每个小时过10分执行一次
0 0/32 8,12 * * ? ----------每天8:32,12:32 执行一次
0 0/2 * * * ?--------------每2分钟执行一次
0 0 12 * * ?---------------在每天中午12:00触发 
0 15 10 ? * *---------------每天上午10:15 触发 
0 15 10 * * ?---------------每天上午10:15 触发 
0 15 10 * * ? *---------------每天上午10:15 触发 
0 15 10 * * ? 2005---------------在2005年中的每天上午10:15 触发 
0 * 14 * * ?---------------每天在下午2:00至2:59之间每分钟触发一次 
0 0/5 14 * * ?---------------每天在下午2:00至2:59之间每5分钟触发一次 
0 0/5 14,18 * * ?---------------每天在下午2:00至2:59和6:00至6:59之间的每5分钟触发一次 
0 0-5 14 * * ?---------------每天在下午2:00至2:05之间每分钟触发一次 
0 10,44 14 ? 3 WED---------------每三月份的星期三在下午2:00和2:44时触发 
0 15 10 ? * MON-FRI---------------从星期一至星期五的每天上午10:15触发 
0 15 10 15 * ?---------------在每个月的每15天的上午10:15触发 
0 15 10 L * ?---------------在每个月的最后一天的上午10:15触发 
0 15 10 ? * 6L---------------在每个月的最后一个星期五的上午10:15触发 
0 15 10 ? * 6L 2002-2005---------------在2002, 2003, 2004 and 2005年的每个月的最后一个星期五的上午10:15触发 
0 15 10 ? * 6#3---------------在每个月的第三个星期五的上午10:15触发 
0 0 12 1/5 * ?---------------从每月的第一天起每过5天的中午12:00时触发 
0 11 11 11 11 ?---------------在每个11月11日的上午11:11时触发
View Code

6.2 CronTrigger构建

可以使用TriggerBuilder 来定义CronTrigger对象。示例如下:

技术分享
import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*:

trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 0/2 8-17 * * ?"))
    .forJob("myJob", "group1")
    .build();
    
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(dailyAtHourAndMinute(10, 42))
    .forJob(myJobKey)
    .build();
    
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 42 10 * * ?"))
    .forJob(myJobKey)
    .build();
    
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY, 10, 42))
    .forJob(myJobKey)
    .inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))
    .build();

trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 42 10 ? * WED"))
    .inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))
    .forJob(myJobKey)
    .build();    
View Code

6.3 CronTrigger Misfire Instruction

CronTrigger的未启动指令包含:

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_DO_NOTHING
MISFIRE_INSTRUCTION_FIRE_NOW
MISFIRE_INSTRUCTION_SMART_POLICY

未启动指令的使用:

技术分享
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 0/2 8-17 * * ?")
        .withMisfireHandlingInstructionFireAndProceed())
    .forJob("myJob", "group1")
    .build();
View Code

Quartz使用(3) - Quartz核心接口Trigger