Quartz的CronScheduleBuilder和Cron表达式(五)上

简介: Quartz的CronScheduleBuilder和Cron表达式(五)上

一. 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();
    }
}


一.三 控制台打印输出


image.png

发现,每隔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 ?"))

image.png


变成了,每隔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 ?"))


控制台打印输出:


image.png

发现,任务根本没有执行。


我们仅仅改变了 cronSchedule() 参数里面的字符串表达式值,就可以控制整个作业调度的运行时间了。


当我们需要运行某个作业调度时,只需要改变 cronSchedule() 方法里面的 表达式值就可以了,非常方便。


关于 cron 表达式,下面,我们重点讲解一下。


二. Cron 表达式

二.一 Cron 表达式的简短介绍

cron,是 crontab 的缩写, 是一种表示时间的方式。 共有6个或者7个值,按照从左到右的顺序,依次为: 秒,分,时,日,月,周,年。


共7个,其中,年可以省略不写(变成了6个)。 各个值之前,用空格进行分开。


注意,cron表达式与系统也有关系,如 Linux 系统的 cron表达式,是分,时,日,月,周,年,没有秒。


这儿,我们只讨论 Quartz框架里面的cron表达式的意义。


在编写Cron 表达式之前,我们需要准确的知道并且描述出来,作业任务执行的准确中文时间是什么(就是可以用中文表达出来), 如几点几分,哪一天的几点几分,2月第三周的星期几的几点几分 等。 只有知道了中文时间,才可以写对应的表达式。


编写Cron 表达式, 先定义好六个格, _ _ _ _ _ _ ,每一个格子里面从左到右,依次放的是 秒,分,时,日,月,周 (年通常是不写的)。


然后将中文时间,依次对应,放置到格子里面即可。


可是,如何把中文时间,解释成数字,放置到对应的格子里面呢?


我们需要知道,每个格子可以放置什么内容 (你不能瞎放,瞎放程序不识别,会报错的)。


二.二 Cron表达式各个单位值的取值范围

image.png


二.三 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表达式
cron表达式: 定时任务触发时间的一个字符串表达形式 corn表达式是一个字符串,分为6或7个域,每一个域代表一个含义 结构:cron从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份
cron表达式
|
1月前
|
JSON fastjson Java
FastJson 完全学习指南(初学者从零入门)
摘要:本文是FastJson的入门学习指南,主要内容包括: JSON基础:介绍JSON格式特点、键值对规则、数组和对象格式,以及嵌套结构的访问方式。FastJson是阿里巴巴开源的高性能JSON解析库,具有速度快、功能全、使用简单等优势,并介绍如何引入依赖,如何替换Springboot默认的JackJson。 核心API: 序列化:将Java对象转换为JSON字符串,演示对象、List和Map的序列化方法; 反序列化:将JSON字符串转回Java对象,展示基本对象转换方法;
|
Java 数据库连接 测试技术
SpringBoot 3.3.2 + ShardingSphere 5.5 + Mybatis-plus:轻松搞定数据加解密,支持字段级!
【8月更文挑战第30天】在数据驱动的时代,数据的安全性显得尤为重要。特别是在涉及用户隐私或敏感信息的应用中,如何确保数据在存储和传输过程中的安全性成为了开发者必须面对的问题。今天,我们将围绕SpringBoot 3.3.2、ShardingSphere 5.5以及Mybatis-plus的组合,探讨如何轻松实现数据的字段级加解密,为数据安全保驾护航。
962 1
|
消息中间件 存储 数据库
深入学习RocketMQ的底层存储设计原理
文章深入探讨了RocketMQ的底层存储设计原理,分析了其如何通过将数据和索引映射到内存、异步刷新磁盘以及消息内容的混合存储来实现高性能的读写操作,从而保证了RocketMQ作为一款低延迟消息队列的读写性能。
|
9月前
|
供应链 监控 数据挖掘
1688 商品详情接口系列(1688 API)
1688商品详情接口系列(1688 API)是阿里巴巴旗下批发电商平台提供的强大工具,支持开发者、商家获取商品的详细信息。通过商品基本信息、价格库存、图片和描述查询接口,用户可以精准高效地获取商品数据,涵盖电商运营、数据分析、市场调研等领域,极大提升工作效率。示例代码展示了如何使用Python调用这些接口,助力电商平台整合、价格监控、商品展示优化及库存管理等应用场景。
|
SQL Java 数据库连接
成功解决:was not registered for synchronization because synchronization is not active
这篇文章是关于解决Mybatis在同步过程中出现"was not registered for synchronization because synchronization is not active"错误的技术博客。
成功解决:was not registered for synchronization because synchronization is not active
|
SQL druid Java
解决 ‘The last packet successfully received from the server was xxx milliseconds ago‘ 问题
解决 ‘The last packet successfully received from the server was xxx milliseconds ago‘ 问题
6673 0
|
Python
【Python 3】解决FeatureNotFound: Couldn‘t find a tree builder with the features you requested: lxml.
文章讨论了在使用Python的BeautifulSoup库时遇到的"Couldn't find a tree builder with"错误,并提供了解决方案。
794 0
|
Java 关系型数据库 MySQL
基于springboot财务管理系统
基于springboot财务管理系统
基于springboot财务管理系统
|
SQL 监控 关系型数据库
深入理解MySQL:核心技术与实战应用
第一章:MySQL概述 1.1 MySQL简介 简要介绍MySQL的起源、发展历程和它在现代数据库领域中的位置