Unix Cron 与 Spring Cron

118 阅读4分钟

一、类 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