一、类 Unix 系统中的 Cron 命令
Cron 最早诞生于 Unix 中,是对于简单任务调度执行的一种结构化抽象,由于表达能力强又易理解,类 Unix 操作系统和软件库(包括 Spring Framework)大量采用了它的任务调度方法,成为了系统与程序的工具级标配能力。通过使用 Cron 表达式,程序员可以快速安排任务在特定日期和时间运行。
作为 Unix 上的一种基础命令,Cron 以守护进程的方式运行。这意味着只需启动一次,它就会在后台持续运行。该进程利用 crontab 读取日程计划表并启动任务。
cron 计划表是一个简单的文本文件,Linux 下位于 /var/spool/cron/crontabs。终端用户无法直接编辑 crontab 文件,需要使用 crontab 命令来访问它:
crontab -e
crontab 中的每一行都是一个任务计划条目,包含一个表达式和一个要运行的命令,比如这个每分钟执行一次的计划:
* * * * * /usr/local/ispconfig/server/server.sh
二、Unix Cron 表达式
作为区分,这里重点介绍下 Unix Cron,Cron 的使用方法可以迁移出来,参考 man 文档。
1、字段构成
Unix Cron 表达式由五部分构成:minute (0-59), hour (0-23), day of the month (1-31), months (1-12 or names), and day of the week (0-7 or names)。
field allowed values
----- --------------
minute 0-59
hour 0-23
day of month 1-31
month 1-12 (or names, see below)
day of week 0-7 (0 or 7 is Sun, or use names)
每个字段用空格分隔,也就是这种格式:
<minute> <hour> <day-of-month> <month> <day-of-week>
2、特殊字符
Cron 表达式设计了这些特殊字符用于强化表达能力:
- *(all)表示每个时间单位都会发生,但在 <day-of-month> 和 <day-of-week> 一般用「?」来代替
- 例如,<minute> 字段中的「*」表示「每分钟」
- ? (any)用于 <day-of-month> 和 <day-of-week> 字段,表示任意值
- 例如,如果我们想在「每月 5 号」启动一个脚本,而不管这一天是星期几,我们就在 <day-of-week> 字段中指定一个「?」
- -(range)代表数值范围,两端边界包含在内
- 例如,<hour> 字段中填写 10-12 代表十点、十一点和十二点
- ,(values)代表多值。
- 例如,<day-of-week> 字段中填写 MON,WED,FRI 代表一周中的星期一、星期三和星期五
- /(increments)代表增量数值
- 例如,<minute> 中填写「5/15」一小时中的第 5 分钟、20 分钟、35 分钟和 50 分钟
- L(last)在不同的字段中都代表最后的意思
- 例如,「6L」在 <day-of-week> 中代表上个周五
- 「L-2」代表本月倒数第二天
- W(weekday)用于确定每个月与给定日期最接近的下个工作日
- 例如,「1W」在 <day-of-week> 中表示该月 1 号最近的一个工作日,如果 1 号是周六,则任务开始于 3 号(不会跳回到上个月);如果1 号是周四,则任务开始于 2 号
- # 用于表示每个月发生在第几周的工作日
- 例如,本月第三个周五可以用「6#3」来表示
另外,Cron 还内置了这些字符串用于快速表达:
string meaning
------ -------
@reboot Run once, at startup.
@yearly Run once a year, "0 0 1 1 *".
@annually (same as @yearly)
@monthly Run once a month, "0 0 1 * *".
@weekly Run once a week, "0 0 * * 0".
@daily Run once a day, "0 0 * * *".
@midnight (same as @daily)
@hourly Run once an hour, "0 * * * *".
三、Spring Cron 表达式
Unix Cron 有一个局限性就是没有秒级任务控制字段,Spring Cron 在这基础上做了扩展,增加了秒级控制,表达式控制字段变成了second, minute, hour, day, month, and weekday。
┌───────────── second (0-59)
│ ┌───────────── minute (0 - 59)
│ │ ┌───────────── hour (0 - 23)
│ │ │ ┌───────────── day of the month (1 - 31)
│ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC)
│ │ │ │ │ ┌───────────── day of the week (0 - 7)
│ │ │ │ │ │ (0 or 7 is Sunday, or MON-SUN)
│ │ │ │ │ │
* * * * * *
要在 Spring 中调度周期性后台任务,我们就可以向 @Scheduled 注解传递一个 Cron 表达式。可以参照 scheduling-enable-annotation-support 文档。
Spring Cron 使用方法与 Unix Cron 无异。
四、Spring Cron 表达式举例
在 Spring 5.3 后,对 Cron 表达式做了增强,可参见 new-in-spring-5-3-improved-cron-expressions。
下面给出一些官方提供的示例:
"0 0 * * * *"= the top of every hour of every day."*/10 * * * * *"= every ten seconds."0 0 8-10 * * *"= 8, 9 and 10 o'clock of every day."0 0 6,19 * * *"= 6:00 AM and 7:00 PM every day."0 0/30 8-10 * * *"= 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day."0 0 9-17 * * MON-FRI"= on the hour nine-to-five weekdays"0 0 0 25 12 ?"= every Christmas Day at midnight"0 0 0 L * *"= last day of the month at midnight"0 0 0 L-3 * *"= third-to-last day of the month at midnight"0 0 0 1W * *"= first weekday of the month at midnight"0 0 0 LW * *"= last weekday of the month at midnight"0 0 0 * * 5L"= last Friday of the month at midnight"0 0 0 * * THUL"= last Thursday of the month at midnight"0 0 0 ? * 5#2"= the second Friday in the month at midnight"0 0 0 ? * MON#1"= the first Monday in the month at midnight