Quartz(三)cron表达式

接上一篇,咱们说了一下quartz的真实模型如下

在实际使用过程中,一个Job并不会被多个JobDetail所关联;实际生产中,还是以一个Job可以被多个Trigger 触发,一个JobDaetail只关联一个Job;


接下来咱们说说Trigger,首先,打开Trigger看看都实现了哪些东西

仔细查看,发现其中,最主要的核心就是CoreTrigger接口,接下来咱们就重点看一下该接口下的四个实现;

*****CronTriggerImpl (org.quartz.impl.triggers)
***SimpleTriggerImpl (org.quartz.impl.triggers)
DailyTimeIntervalTriggerImpl (org.quartz.impl.triggers)
CalendarIntervalTriggerImpl (org.quartz.impl.triggers)

官方文档默认的就是SimpleTriggerImpl,那下面咱们重点看一下CronTriggerImpl;

            //0 1 2 3
            Trigger trigger = TriggerBuilder.newTrigger()
//                    .withIdentity("trigger1", "group1")
                    .startNow()
                    .withSchedule(
                            //根据固定的时间间隔和一定的重复次数去调动任务
                            SimpleScheduleBuilder
                            .simpleSchedule()
                            .withIntervalInSeconds(1)
                            .withRepeatCount(1)
//                            .repeatForever()
                    )
                    .build();

官方文档默认的是SimpleScheduleBuilder咱们可以猜测,是否有一个CronScheduleBuilder与其对应呢?咱们编写代码测试一下;

  //0 1 2 3
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger1", "group1")
                    .startNow()
                    .withSchedule(
                        CronScheduleBuilder.cronSchedule("")
                    )
                    .build();
​
            scheduler.scheduleJob(job, trigger);

发现的确有这么个玩意儿,那下面咱们重点看一下CronScheduleBuilder,点进源码

它有CronExpression这么个玩意儿,咱们点进去看看

这个类上面的注释基本说明白了他所表达的意思,有兴趣的小伙伴可以点击进行阅读,下面,咱们通过代码测试一下吧;

/**
 * @author: shaoyun_Wang
 * @create: 2022-05-29 21:45
 * @Description:
 */
public class QuartzTest5 {
​
    public static void main(String[] args) {
​
        try {
​
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
​
            scheduler.start();
​
            JobDetail job = JobBuilder.newJob(HelloJob.class)
                    .withIdentity("job1", "group1")
                    .build();
​
            //0 1 2 3
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger1", "group1")
                    .startNow()
                    .withSchedule(
                        CronScheduleBuilder.cronSchedule("* * * * * ? *")
                    )
                    .build();
​
            scheduler.scheduleJob(job, trigger);
​
            TimeUnit.SECONDS.sleep(3);
            scheduler.shutdown();
​
        } catch (Exception se) {
            se.printStackTrace();
        }
    }
}
​

运行结果:

Hello.execute!!!2022.06.04 12:25:28DefaultQuartzScheduler_Worker-1trigger1
Hello.execute!!!2022.06.04 12:25:29DefaultQuartzScheduler_Worker-2trigger1
Hello.execute!!!2022.06.04 12:25:30DefaultQuartzScheduler_Worker-3trigger1
Hello.execute!!!2022.06.04 12:25:31DefaultQuartzScheduler_Worker-4trigger1
​

3s执行了4次;要想明白是如何执行的,咱们就得弄清楚cron表达式,这边我根据源码进行了整理

'*' 字符用于指定所有值。例如,分钟字段中的“*”表示“每分钟”。
'?'日期和星期几字段允许使用字符。它用于指定“无特定值”。当您需要在两个字段之一中指定某些内容而不在另一个字段中指定内容时,这很有用。
'-' 字符用于指定范围 例如,小时字段中的“10-12”表示“小时 10、11 和 12”。
',' 字符用于指定附加值。例如,星期几字段中的“MON,WED,FRI”表示“星期一、星期三和星期五”。
'/' 字符用于指定增量。例如,秒字段中的“0/15”表示“秒 0、15、30 和 45”。秒字段中的“5/15”表示“5、20、35 和 50 秒”。在'/'之前指定'*'等同于指定 0 是开始的值。本质上,对于表达式中的每个字段,都有一组可以打开或关闭的数字。对于秒和分钟,数字范围从 0 到 59。对于小时 0 到 23,对于月份中的天 0 到 31,以及月份 0 到 11(JAN 到 DEC)。"/" 字符只是帮助您打开给定集中的每个“第 n 个”值。因此,月份字段中的“76”仅打开月份“7”,并不意味着每 6 个月一次.
'L' 字符允许用于日期和星期几字段。这个字符是“last”的简写,但在两个字段中都有不同的含义。例如,day-of-month 字段中的值“L”表示“月的最后一天”——非闰年 1 月的第 31 天,2 月的第 28 天。如果单独在星期几字段中使用,它仅表示“7”或“SAT”。但如果在星期几字段中使用另一个值,则表示“本月的最后 xxx 天”——例如“6L”表示“本月的最后一个星期五”。您还可以指定与该月最后一天的偏移量,例如“L-3”,表示日历月的倒数第三天。使用“L”选项时,重要的是不要指定列表或值范围,因为您会得到令人困惑的意外结果。
日期字段允许使用“W”字符。此字符用于指定距给定日期最近的工作日(周一至周五)。例如,如果您将“15W”指定为日期字段的值,则其含义是:“距每月 15 日最近的工作日”。因此,如果 15 日是星期六,触发器将在 14 日星期五触发。如果 15 日是星期日,触发器将在 16 日星期一触发。如果 15 号是星期二,那么它将在 15 号星期二触发。但是,如果您将“1W”指定为日期的值,并且第 1 天是星期六,则触发器将在第 3 天的星期一触发,因为它不会“跳过”一个月的日期边界。 'W' 字符只能在日期为一天而不是日期范围或列表时指定。'L' 和 'W' 字符也可以组合用于 day-of-month 表达式以产生 'LW',它转换为“本月的最后一个工作日”。
星期几字段允许使用 '' 字符。此字符用于指定一个月中的“第 n 个”XXX 天。例如,星期几字段中的“63”值表示该月的第三个星期五(第 6 天 = 星期五,“3” = 该月的第三个星期五)。其他示例:“21” = 每月的第一个星期一,“45” = 每月的第五个星期三。请注意,如果您指定“5”并且该月没有给定的星期几中的 5 个,则该月不会发生触发。如果使用 '' 字符,则星期字段中只能有一个表达式(“31,63”无效,因为有两个表达式)。