# Cron触发器

如果您需要一个基于类似日历的概念而不是基于简单触发器的精确指定间隔重复的作业触发方案,Cron触发器通常比简单触发器更有用。

使用Cron触发器,您可以指定触发时间表,例如“每周五中午”、“每周日和上午9:30”,甚至“1月期间每周一、周三和周五上午9:00到10:00之间的每5分钟”。

即使如此,与简单触发器一样,Cron触发器有一个startTime,它指定计划何时生效,以及一个(可选)endTime,它指明计划何时应停止。

# Cron表达式

Cron表达式用于配置Cron触发器的实例。Cron表达式是由七个子表达式组成的字符串,这些子表达式描述了方案的各个细节。这些子表达式用空格分隔,表示:

  1. 分钟

  2. 小时

  3. 一月中的某一天

  4. 一周中的某一天

  5. 年份(可选字段)

字符串“0 0 12?* WED”是一个完整的Cron表达式示例,意思是“每周三12:00:00 pm”。

**单个子表达式可以包含范围和(或)列表。**例如,上一个示例中的星期几字段(WED)可以替换为MON-FRIMON,WED,FRI,甚至MON-WED,SAT

**通配符(“*”字符)可用于表示此字段的“所有”可能值。**因此,上一示例中“月”字段中的“*”字符仅表示“每月”。因此,“星期日”字段中的“*”显然意味着“一周中的每一天”。

**所有字段都有一组可以指定的有效值。**这些值应该相当明显,例如0到59代表秒和分钟,0到23代表小时。月日可以是1-31的任何值,但您需要注意给定月份有多少天!可以将月份指定为介于0和11之间的值,或使用字符串JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC。可以将一周中的天数指定为介于1和7之间的值(1=星期日),也可以使用字符串SUNMONTUEWEDTHUFRISAT

一个完整的Cron表达式的示例例如,如果在“分钟”字段中输入“0/15”,则表示“从0分钟开始,每15分钟”。如果在“分钟”字段中使用“3/20”,则表示“从第3分钟开始,每20分钟”,或者换句话说,这与在“分钟数”字段中指定“3,23,43”相同。注意微妙之处,“/35”并不意味着“每35分钟”-它意味着“从0分钟开始,一小时的每35分钟”,或者换句话说,与指定“0,35”相同。

**“?”月日和星期日字段允许使用字符。**用于指定“无特定值”。当您需要在两个字段中的一个字段中指定内容,而不是另一个字段时,这很有用。请参见下面的示例(和CronTriggerJavaDoc)以获得澄清。

**月日和星期日字段允许使用“L”字符。**这个字符是“last”的缩写,但在这两个字段中每个字段都有不同的含义。例如,“月日”字段中的值“L”表示“一个月的最后一天”——1月的第31天,非闰年的2月的第28天。如果在星期几字段中单独使用,它只表示“7”或“SAT”。但如果在星期几字段中使用另一个值,则表示“该月的最后xxx天”,例如“6L”或“FRIL”都表示“该月中的最后一个星期五”。您还可以指定从当月最后一天开始的偏移量,例如“L-3”,这意味着日历月的第三天到最后一天。使用“L”选项时,重要的是不要指定列表或值范围,因为您会得到令人困惑或意外的结果。

**“W”用于指定最接近给定日期的工作日(周一至周五)。**例如,如果要指定“15W”作为月日字段的值,则其含义为:“最接近月15日的工作日”。

**“#”用于指定当月的第n个XXX工作日。**例如,星期几字段中的值“6#3”或“FRI#3”表示“每月的第三个星期五”。

还有几个表达式及其含义的示例,您可以在Java文档的org.quartz.CronExpression中找到更多。

# Cron表达式例子

Cron触发器示例1——一个创建触发器的表达式,该触发器只需每5分钟触发一次:

0 0/5 * * * ?

Cron触发器示例2——一个表达式,用于创建每5分钟触发一次的触发器,每分钟后10秒触发一次(即上午10:00:10、上午10:05:10等):

10 0/5 * * * ?

Cron触发器示例3——一个表达式,用于创建在每周三和周五10:30、11:30、12:30和13:30触发的触发器:

0 30 10-13? * WED,FRI

Cron触发器示例4——一个创建触发器的表达式,该触发器在每月5日和20日上午8点到10点之间每半小时触发一次。请注意,触发器不会在上午10:00启动,仅在8:00、8:30、9:00和9:30启动:

0 0/30 8-9 5,20 * ?

请注意,有些日程安排要求太复杂,无法用一个触发器来表达,例如“上午9点到10点之间每5分钟一次,下午1点到10点钟之间每20分钟一次”。此场景中的解决方案是直接创建两个触发器,并注册它们以运行同一个作业。

# 构建Cron触发器

Cron触发器实例是使用TriggerBuilder(用于触发器的主属性)和CronScheduleBuilder(用于触发器的特定属性)构建的。要以DSL样式使用这些生成器,请使用静态导入:

import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*;

每天早上8点到下午5点,每隔1分钟触发一次:

trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 0/1 8-17 * * ?"))
    .forJob("myJob", "group1")
    .build();

建立一个触发器,每天上午10:42触发:

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();

构建一个触发器,该触发器将在周三上午10:42在系统默认以外的时区启动:

trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY, 10, 42))
    .forJob(myJobKey)
    .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
    .build();

或者

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

# Cron触发器无触发指令

以下说明可用于通知Quartz在Cron触发器发生无触发时应采取的措施。(在本教程的“更多关于触发器”部分中介绍了无触发情况)。这些指令被定义为Cron触发器本身的常量(包括描述其行为的Java文档)。说明包括:

Cron触发器的无触发指令常量:

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_DO_NOTHING
MISFIRE_INSTRUCTION_FIRE_NOW

所有触发器也具有Trigger.MISFIRE_INSTRUCTION_SMART_POLICY指令可用,该指令也是所有触发器类型的默认指令。Cron触发器将“智能策略”指令解释为MISFIRE_instruction_FIRE_NOW。Java文档的CronTrigger.updateAfterMisfire()方法解释了此行为的确切细节。

在构建Cron触发器时,可以将无触发指令指定为简单计划的一部分(通过CronSchedulerBuilder):

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

微信公众号

QQ交流群
原创网站开发,偏差难以避免。

如若发现错误,诚心感谢反馈。

愿你倾心相念,愿你学有所成。

愿你朝华相顾,愿你前程似锦。