CronTrigger通常比SimpleTrigger更有用,如果您需要基于类似日历的概念而不是精确指定的SimpleTrigger间隔重复发生的作业计划。
使用CronTrigger,您可以指定触发时间表,例如“每周五中午”,或“每个工作日和上午9:30”,甚至“每周一,周三上午9:00到上午10:00之间每隔5分钟”和1月的星期五“。
即便如此,像SimpleTrigger一样,CronTrigger有一个startTime,用于指定计划何时生效,以及一个(可选的)endTime,用于指定何时停止计划。
Cron Expressions
Cron-Expressions用于配置CronTrigger的实例。Cron-Expressions是实际上由七个子表达式组成的字符串,用于描述计划的各个细节。这些子表达式用空格分隔,表示:
- Seconds
- Minutes
- Hours
- Day-of-Month
- Month
- Day-of-Week
- Year (optional field)
完整的cron表达式的一个例子是字符串 “0 0 12?* WED“ - 表示”每周三中午12:00:00“。
单个子表达式可以包含 ranges and/or lists 。例如,前一周中的星期字段(其中读取“WED”)示例可以替换为“MON-FRI”,“MON,WED,FRI”或甚至“MON-WED,SAT”。
通配符(' '字符)可用于表示该字段的“每个”可能值。因此,前一个例子的“月”字段中的' '字符仅表示“每个月”。因此,“周日”字段中的“*”显然意味着“一周中的每一天”。
所有字段都有一组可以指定的有效值。这些值应该相当明显 - 例如秒和分钟的数字0到59,以及小时的值0到23。每月的日期可以是任何值1-31,但您需要注意一个月内的天数!月份可以指定为0到11之间的值,或者使用字符串JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV和DEC。星期几可以指定为1到7之间的值(1 =星期日)或使用字符串SUN,MON,TUE,WED,THU,FRI和SAT。
'/'字符可用于指定值的增量。例如,如果在“分钟”字段中输入“0/15”,则表示“每小时的第15分钟,从零分钟开始”。如果您在“分钟”字段中使用“3/20”,则表示“每小时20分钟,从第3分钟开始” - 或者换句话说,它与在“分钟”中指定“3,23,43”相同领域。注意“ / 35”所暗示的微妙*并不意味着“每35分钟” - 它意味着“每小时的第35分钟,从零分钟开始” - 或者换句话说与指定'0,35'相同。
'?' 允许使用字符表示日期和星期几字段。它用于指定“无特定值”。当您需要在两个字段之一中指定某些内容而不是另一个字段时,这非常有用。请参阅下面的示例(和CronTrigger JavaDoc)以获得说明。
“L”字符允许用于日期和星期几字段。这个字符是“last”的简写,但它在两个字段的每一个中都有不同的含义。例如,日期字段中的值“L”表示“月份的最后一天” - 1月31日,非闰年2月28日。如果在星期几字段中单独使用,则仅表示“7”或“SAT”。但如果在星期几字段中使用另一个值后,则表示“该月的最后一个xxx日” - 例如“6L”或“FRIL”均表示“该月的最后一个星期五”。您还可以指定从该月的最后一天开始的偏移量,例如“L-3”,这意味着该日历月的倒数第三天。使用“L”选项时,重要的是不要指定列表或值范围,因为您会得到令人困惑/意外的结果。
'W'用于指定最接近给定日期的工作日(周一至周五)。例如,如果您指定“15W”作为日期字段的值,则含义为:“最近的工作日到该月的15日”。
'#'用于指定月份的“第n个”XXX个工作日。例如,星期几字段中的“6#3”或“FRI#3”的值意味着“该月的第三个星期五”。
以下是表达式及其含义的更多示例 - 您可以在JavaDoc中找到更多org.quartz.CronExpression。
Example Cron Expressions
CronTrigger 示例1 - 用于创建触发器的表达式,该触发器每5分钟触发一次
“0 0/5 * * * ?”
CronTrigger 示例2 - 用于创建触发器的表达式,该触发器在每分钟10秒后(即上午10:00:10,上午10:05:10等)每隔5分钟触发一次。
“10 0/5 * * * ?”
CronTrigger 示例3 - 用于创建触发器的表达式,该触发器在每周三和周五的10:30,11:30,12:30和13:30触发。
“0 30 10-13 ? * WED,FRI”
CronTrigger 示例4 - 用于创建触发器的表达式,该触发器在每个月的5日和20日上午8点到上午10点之间每半小时触发一次。请注意,触发器不会在上午10:00触发,仅在 8:00,8:30,9:00和9:30触发
“0 0/30 8-9 5,20 * ?”
请注意,某些计划要求过于复杂,无法通过单个触发器表达 - 例如“上午9:00至上午10:00之间每隔5分钟,下午1:00至晚上10:00之间每20分钟”。此方案中的解决方案是简单地创建两个触发器,并注册它们以运行相同的作业。
Building CronTriggers
CronTrigger实例是使用TriggerBuilder(用于触发器的主要属性)和CronScheduleBuilder(用于特定于CronTrigger的属性)构建的。要以DSL样式使用这些构建器,请使用静态导入:
import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*:
建立一个触发器,每天上午8点到下午5点之间每隔一分钟触发一次:
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 0/2 8-17 * * ?"))
.forJob("myJob", "group1")
.build();
构建一个触发器,每天上午10:42触发:
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(dailyAtHourAndMinute(10, 42))
.forJob(myJobKey)
.build();
or -
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 42 10 * * ?"))
.forJob(myJobKey)
.build();
构建一个触发器,该触发器将在星期三上午10点42分在TimeZone中触发,而不是系统的默认值:
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY, 10, 42))
.forJob(myJobKey)
.inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
.build();
or -
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 42 10 ? * WED"))
.inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
.forJob(myJobKey)
.build();
CronTrigger Misfire Instructions
以下说明可用于告知Quartz当CronTrigger发生未触发时它应该做什么。(在本教程的“更多关于触发器”部分中介绍了失火情况)。这些指令在CronTrigger本身定义为常量(包括描述其行为的JavaDoc)。说明包括:CronTrigger的失火指令常量
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_DO_NOTHING
MISFIRE_INSTRUCTION_FIRE_NOW
所有触发器都有Trigger.MISFIRE_INSTRUCTION_SMART_POLICY指令供使用,该指令也是所有触发器类型的默认指令。“智能策略”指令由CronTrigger解释为MISFIRE_INSTRUCTION_FIRE_NOW。CronTrigger.updateAfterMisfire()方法的JavaDoc解释了此行为的确切详细信息。
在构建CronTriggers时,您将misfire指令指定为简单计划的一部分(通过CronSchedulerBuilder):
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 0/2 8-17 * * ?")
..withMisfireHandlingInstructionFireAndProceed())
.forJob("myJob", "group1")
.build();