Quartz的CronScheduleBuilder和Cron表达式(五)
勿以恶小而为之,勿以善小而不为--------------------------刘备
劝诸君,多行善事积福报,莫作恶
上一章简单介绍了 Quartz的Scheduler的关闭和挂起,并发控制(四),如果没有看过,请观看上一章
一. CronScheduleBuilder
前面用的调度器建造器是 SimpleScheduleBuilder,需要用类方法的形式自己拼接相应的调度,多久执行一次,执行几次,是通过方法来设置的。
其实,调度实际上就是一个时间的表达式。 时间的常用单位是,秒,分,时,天,月,周,年, 如果我们可以用一个表达式,将这些时间单位拼接在一起,让程序识别这个表达式,是否就可以变成时间调度,然后去执行作业调度了呢?
是的,可以, 这个表达式就是 Cron 表达式。
创建 Cron 表达式的 调度,就是 CronSchedulerBuilder 。
这个Cron 表达式,非常强大,也非常简单。
下面,老蝴蝶就讲解一下 CronSchedulerBuilder 和其对应的 Cron 表达式。
先写一个例子,来演示一下 Cron表达式的用法。
一.一 作业任务接口
//cron 表达式
public class MyJob12 implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//要做的事,是打印当前的时间
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//格式化时间
String dateString=sdf.format(new Date());
System.out.println("备份数据库的时间是:"+dateString);
}
}
一.二 主程序测试
//CronSchedulerBuilder 测试
public class SchedulerDemo12 {
public static void main(String[] args) throws Exception{
//获取Scheduler
Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
// 创建 JobDetail
JobDetail jobDetail=JobBuilder.newJob(MyJob12.class)
.withIdentity("job1","group1")
.build();
//创建 Trigger
Trigger trigger= TriggerBuilder.newTrigger()
.withIdentity("trigger1","group1") //设置标识
.startNow()
//里面定义的这个式子, 0/3 * * * * ? 就是cron表达式。
.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
.build();
//关联 job和 trigger
scheduler.scheduleJob(jobDetail,trigger);
//启动 scheduler
scheduler.start();
}
}
一.三 控制台打印输出
发现,每隔3秒执行一次任务。
这个3秒,是否与表达式里面,唯一出现的数字(0/3) 里面的3 有关联呢?
再写几个表达式,类比一下。
如,今天是4月29号,改变4月29号试试看:
//里面定义的这个式子, 0/3 * * * * ? 就是cron表达式。
//.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
//重新改写一下,改成4月29号
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * 29 4 ?"))
变成了,每隔2秒执行一次任务了。
将日期改成 4月30号,看看效果
//里面定义的这个式子, 0/3 * * * * ? 就是cron表达式。
//.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
//重新改写一下,改成4月29号
//.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * 29 4 ?"))
//再次改变,试一下
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * 30 4 ?"))
控制台打印输出:
发现,任务根本没有执行。
我们仅仅改变了 cronSchedule() 参数里面的字符串表达式值,就可以控制整个作业调度的运行时间了。
当我们需要运行某个作业调度时,只需要改变 cronSchedule() 方法里面的 表达式值就可以了,非常方便。
关于 cron 表达式,下面,我们重点讲解一下。
二. Cron 表达式
二.一 Cron 表达式的简短介绍
cron,是 crontab 的缩写, 是一种表示时间的方式。 共有6个或者7个值,按照从左到右的顺序,依次为: 秒,分,时,日,月,周,年。
共7个,其中,年可以省略不写(变成了6个)。 各个值之前,用空格进行分开。
注意,cron表达式与系统也有关系,如 Linux 系统的 cron表达式,是分,时,日,月,周,年,没有秒。
这儿,我们只讨论 Quartz框架里面的cron表达式的意义。
在编写Cron 表达式之前,我们需要准确的知道并且描述出来,作业任务执行的准确中文时间是什么(就是可以用中文表达出来), 如几点几分,哪一天的几点几分,2月第三周的星期几的几点几分 等。 只有知道了中文时间,才可以写对应的表达式。
编写Cron 表达式, 先定义好六个格, _ _ _ _ _ _ ,每一个格子里面从左到右,依次放的是 秒,分,时,日,月,周 (年通常是不写的)。
然后将中文时间,依次对应,放置到格子里面即可。
可是,如何把中文时间,解释成数字,放置到对应的格子里面呢?
我们需要知道,每个格子可以放置什么内容 (你不能瞎放,瞎放程序不识别,会报错的)。
二.二 Cron表达式各个单位值的取值范围
名称 | 是否必须 | 允许值 | 包含的特殊字符 |
---|---|---|---|
秒 | 是 | 0~59 | , / * - |
分钟 | 是 | 0~59 | , / * - |
小时 | 是 | 0~23 | , / * - |
日 | 是 | 1~31 (每月最多是31天) | , / * - ? L W C |
月 | 是 | 1~12 或者英文 JAN~DEC | , / * - |
周 | 是 | 1-7 或者英文SUN~SAT | , / * - ? L C # |
年 | 不 | 空,或者1970~2099 | , / * - |
二.三 Cron表达式各个符号的意义
各个单位值中的特殊字符,是什么意思呢? 都具有的 , / * - 是什么意思呢? 日和周特有的? L和C 是什么意思呢,我们重点讲解一下。
cron 表达式 可以 全部是准确的合法数字,也可以全部是特殊字符,还可以合法数字与特殊字符连用, 这就是cron的强大的地方。
关于合法数字,就是生活中正常的值,不讲解, 只讲解 特殊字符。
二.三.一 特殊字符 *
*, 如果某个格子上的值 是 *, 就表示这个格子包含所有合法的值, 即全部值。
如果 秒格子上是 *,就表示所有的秒都可以取到, 也就是每一秒, 每一秒都会触发。
如果小时格子上是 *,就表示所有的小时都可以取到,也就是每一小时, 每一小时都会触发。
如果天格子上是 *,就表示每一天, 每一天都会触发。
二.三.二 特殊字符 ,
, 是给这个格子指定一个 值列表, 列表的各个值之间,用 , 进行分隔。
如 2,4,5 表示, 可以是2,也可以是4,也可以是5, 即 2时触发,4时也触发,5时也触发。
如果秒格子上是 2,4,5 则表示, 2s时,或者4s时,或者5秒时 触发。
如果天格子上是 2,4,5 则表示,2号,4号,5号都可以触发。
跟CSS样式里面的 ,表示意义一样。
二.三.三 特殊字符 -
-, 是中划线(大键盘数字0旁边的 -号), 用于指定一个范围。
如 2-5, 表示2和3和4和5, 即2,3,4,5 , 是范围时的一种简写形式。
如果秒格子上是 2-5,则表示, 第2秒,第3秒,第4秒,第5秒时触发。
如果月格子上是 2-5, 则表示 第2月,第3月,第4月,第5月时触发。
如果周格子上是 2-5,则表示 这个月的 第二周,第三周,第四周,第五周 时触发。 (注意,有可能某一年的2月28天时只有4个周,没有第五个周,所以一定要注意,表达式本身是否合理)
二.三.四 特殊字符 /
/, 用于递增, 即如 秒格子上的 0,15,30,45 就可以写成 0/15 ,从0开始,每次递增15, 翻译成中文就是每隔 15的意思。
所以,/ 表示的是每隔多少的意思。 A/B, 开始的点是A,间距是B.
如果秒格子上是 0/15, 则表示 从0秒开始,每隔15秒执行一次。
如果天格子上是 1/15,则表示从 1号开始,每隔15天执行一次。 (天格子上,0/15是非法的值). 这次是1号,那么下次就是16号,再下次就可以是 1号(31天),也可以是 2号(30天),也可能是 3号(闰年2月 29天),也可能是4号(平年2月 28天),
一定是间隔15天的,并不一定还是1号循环回来。
二.三.五 特殊字符 ?
? 只能放置于 日或者周上面。 注意,秒,分,时,月,年 这五个值是不会受其他的单个值影响的, 即秒上面是3,
那么无论其他格子上的值是多少,这个秒上面的3都是对的。 但是,日和周就不一样了, 他们两个是可以互相影响的。
如, 日格子上指定值为 31, 周格子上指定 为第一周, 那么这个cron 表达式 按照谁的来呢? 是按照日来,还是按照周来,
还是变成一个死掉的表达式? 都 不可以。 为了避免这样的情况发生, 所以出现了 ? 表达式, 表示放弃维护表达式,
即我并不关心这个值是多少。
如果 日格子上是 ?, 就表示告诉表达式, 你不用管我,你只看周就可以了。
如果 周格子上是 ?, 就表示告诉表达式, 你不用管我, 你只看 日就可以了。
所以,如果当 日上面的值不是?时, 周上面的值肯定是 ?, 如果当周上面的值不是?时,日上面的值肯定是? 号。
但两个格子,不能同时是 ?时。
如果式子是: * * * 3-5 * ?, 此时周上面是?,周放弃维护, 只看日就可以了。 每个月的3号到5号触发。
如果式子是: * * * ? * 3, 此时日上面是?,日放弃维护,只看周就可以了, 表示 每周的星期二触发。
二.三.六 特殊字符 L
L 是 last,最后一个的意思。 只能应用于 日和周上面, 表示最后一天,最后一周。
当然,你也可能会说,秒也有最后一秒啊,小时也有最后一小时啊,为什么不可能用在秒和小时上面,
因为最后一秒是确定的,就是59s, 最后一小时也是确定的,就是23小时, 最后一月也是确定的,就是12月,
直接写确切的数字即可, 不需要用 L 。
日上面的 L,是由月来确定的, 每个月的最后一天是不确定的, 如1月最后一天是31,4月最后一天是30,
用L 这个特殊字符,就不需要开发者自己去写逻辑判断日了。
周上面的 L, 也是由月来确定的, 每个月的最后一周是不确定的, 每个月可能有4周,也可能有5周,还可能有6周,
这都是不确定的,用L 这个特殊字符,就不需要开发者自己去写逻辑判断周了。
日格子上面想表达最后一天的概念时, 只能单独写一个 L, 不能再写其他的东西了。
周格子上面想表达最后一周的概念时, 可以只写一个L, 表示最后一周的那几天,都触发,
也可以确切地表示最后一周的星期几触发, 需要添加 数字
如 2L, 表示最后一周的星期一, 3L 表示最后一周的星期天, 最后一周的其他天并不能触发。
如果是6L, 而这个月最后一周没有周五,到周三就结束了,那么就去找上一周的周五。
二.三.七 特殊字符 w
W,只能应用于 日 格子上。 W,表示的是 work, 工作日。 指的就是周一到周五,正常的工作日。
注意,这儿工作日与国家法定节假日是没有关系的,只是星期上的工作日的概念。
前面需要加上一个数字, 数字天W, 表示距离某天最近的工作日。
如 15W,
如果这一月的15号这一天是星期五,正常的工作日,那么就在这一天触发任务。
如果这一月的15号这一天是星期六,不是正常的工作日, 它距离上一个工作日14号(星期五)相差1天,距离下一个工作日17号(下个星期一) 相差2天, 那么就在离它最近的那一个工作日,即14号触发。
如果这一月的15号这一天是星期日,不是正常的工作日,它距离上一个工作日13号(星期五) 相差2天,距离下一个工作日16号(星期一) 相差1天, 那么就在离它最近的那一个工作日,即16号触发。
银行业务,或者公司薪资业务常常用 w 这个特殊字符
二.三.八 特殊字符 LW
LW 这个组合字符 ,只能用于周格子上, 表示本月的最后一个工作日。
L 是本周最后一个,W 表示最后一个工作日, 组合起来,就是 本月的最后一个工作日。
常常用于统计 本月的出勤,流量等统计业务中。
二.三.九 特殊字符 #
# 只能用于 周格子上, 表达第几周的星期几的概念。
由两个部分组成 A#B, A表示星期几, B表示第几个, 即 第B周的星期A 。
常常用于西方不固定的节日上。
如母亲节, 5月的第二个星期天, 那么就可以写成 * * * ? 5 1#2
如父亲节,6月的第三个星期天, 那么就可以写成: * * * ? 6 1#3
二.四 快速创建Cron 表达式
二.四.一 创建方式
将中文时间上的每一个单位从大到小排列一下,依次放置到 每一个格子上即可, 要保证各个格子的单位值是合法的,
总体也是合法的。
如, 某一个作业任务是 , 每年的2月,4月的7号和8号的9点的 15分,40分,45分时触发。
先按照从大到小排列一下:
年: 每年, *,可以省略
周: 指定了天,不能指定周, 用?
月: 2月和4月,可以写成 2,4
日: 7号和8号, 可以写成7,8 或者 7-8
时: 9点, 确切时间,9
分: 15分,40分,45分, 可以写成 15,40,45
秒: 未指定,从0开始, 表示某一分钟的最开始那一秒执行。用 0 (注意, 并不是每一秒执行哈)
那么 就可以写成: 0 15,40,45 7-8 2,4 ?
二.四.二 在线 cron 表达式网址
如果不想自己动手 写cron 表达式, 可以使用在线 cron 网站进行生成。
必应搜索 ‘cron 在线’ 之类的关键词即可:
为避免广告嫌疑,老蝴蝶这儿就不指定了。
三. 分析常见的Cron 表达式
列举一些常见的表达式,来讲解一下。
(表达式参考了 黑马教程的 Quartz框架中的 Quartz 定时任务调度文档中的内容)
表达式 | 意义 |
---|---|
0 0 8 * * ? | 每天早上8点触发 |
0 30 9 * * ? | 每天早上9点半触发 |
0 * 23 * * ? | 每天晚上的11点0分到晚上11点59分,每一分钟触发一次 |
0 0/5 22,23 * * ? | 每天晚上的10点0分到11点55分,及每天晚上11点0分到晚上11点55分,每五分钟触发一次 |
0 0-5 23 * * ? | 每天晚上的11点0分到晚上11点5分,每一分钟触发一次 |
0 10,45 14 ? 3 4 | 每年3月的星期三,下午2点10分和下午2点45分触发 |
0 30 9 ? * 2-5 | 每个月的周一到周五的9点半触发 |
0 30 9 15 * ? | 每个月15号的9点半触发 |
0 55 23 L * ? | 每个月最后一天的晚上11点55分触发 |
0 55 23 ? * 6L | 每个月最后一个周五的晚上11点55分触发 |
0 0 8 ? 5 1#2 | 5月的第二个星期天的早上8点触发,即母亲节那天八点给妈妈发节日快乐 |
0 0 8 ? 6 1#3 | 6月的第三个星期天的早上8点触发,即父亲节那天八点给爸爸发节日快乐 |
四. 母亲节那一天触发的小例子
世上只有一个妈妈好,珍惜吧。 读者们,别忘记这一天给妈妈打电话,发祝福。
四.一 发送祝福 任务
//母亲节快乐的 Cron
public class MyJob88 implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("妈妈,母亲节快乐,您辛苦了!!!");
}
}
四.二 祝福调度主程序
//母亲节快乐的Cron
public class SchedulerDemo88 {
public static void main(String[] args) throws Exception{
//获取Scheduler
Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
// 创建 JobDetail
JobDetail jobDetail=JobBuilder.newJob(MyJob88.class)
.withIdentity("job1","group1")
.build();
//创建 Trigger
Trigger trigger= TriggerBuilder.newTrigger()
.withIdentity("trigger1","group1") //设置标识
.startNow()
//cron 表达式为母亲节
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 8 ? 5 1#2"))
.build();
//关联 job和 trigger
scheduler.scheduleJob(jobDetail,trigger);
//启动 scheduler
scheduler.start();
}
}
四.三 祝福测试
2020年母亲节是5月10号, 老蝴蝶将自己本地计算机的时间改成 5月10号的7点59分。
运行程序,观看控制台的祝福:
谢谢您的观看!!!
上一篇: 源码分析Dubbo服务消费端启动流程
下一篇: 如何只用一行代码让Pandas加速四倍?
推荐阅读
-
Quartz的CronScheduleBuilder和Cron表达式(五)
-
Spring集成Quartz定时任务框架介绍和Cron表达式详解 博客分类: spring
-
Spring集成Quartz定时任务框架介绍和Cron表达式详解 博客分类: spring
-
springboot Quartz动态修改cron表达式的方法
-
springboot Quartz动态修改cron表达式的方法
-
Quartz的cron表达式 博客分类: java quartzSUN工作
-
Quartz的cron时间表达式
-
Spring集成Quartz定时任务框架介绍和Cron表达式详解
-
Spring集成Quartz定时任务框架介绍和Cron表达式详解
-
Quartz的Cron表达式解释