Spring 定时任务scheduled详解

时间:2021-06-03 07:51:50

Spring的定时任务的相关支持是存放在Spring-context.jar中的,默认是关闭状态,使用的话记得开启。

开启定时任务

使用注解@EnableScheduling 即可开启

各方式说明

这里我们使用@Scheduled的方式进行讲解。默认提供了fixedDelay,fixedRate,cron

参阅源代码:

public @interface Scheduled {
String cron() default "";

long fixedDelay() default -1L;

String fixedDelayString() default "";

long fixedRate() default -1L;

String fixedRateString() default "";

long initialDelay() default -1L;

String initialDelayString() default "";
}

fixedDelay

固定延迟,在延迟一段时间后执行定时任务,并不是从定时任务加载后立刻执行。

示例

以下任务是在五秒后开始执行定时任务,并且每五秒执行一次。默认单位是毫秒(后续不在说明,基本都是毫秒)

@Scheduled(fixedDelay=5000)
public void doSomething() {
// something that should execute periodically
}

fixedRate

固定速率执行定时任务,从启动就开始执行,即启动的时候会立刻执行一次。也可以通过参数(initialDelay )进行调整

示例

以下任务自启动开始立刻执行一次,之后每5秒执行一次。

@Scheduled(fixedRate=5000)
public void doSomething() {
// something that should execute periodically
}

以下任务自启动开始,延迟一秒后执行一次,之后每5秒执行一次。

@Scheduled(initialDelay=1000, fixedRate=5000)
public void doSomething() {
// something that should execute periodically
}

cron

Spring 中也支持Cron格式的定时任务,但是切记Spring做了简化,以及优化,与纯cron是有些差异的。以下后给出说明。

  • 解析类:CronSequenceGenerator
/**
* 解析给定的表达式

与纯cron表达式相比,Spring中只支持6位的形式(没有年份的选项)。需要特别注意。

*/

private void parse(String expression) throws IllegalArgumentException {
String[] fields = StringUtils.tokenizeToStringArray(expression, " ");
//判断cron位数
if (!areValidCronFields(fields)) {
throw new IllegalArgumentException(String.format(
"Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression));
}
//设置第一位秒
setNumberHits(this.seconds, fields[0], 0, 60);
//设置第2位分钟
setNumberHits(this.minutes, fields[1], 0, 60);
//设置第3位小时
setNumberHits(this.hours, fields[2], 0, 24);
//设置第4位天
setDaysOfMonth(this.daysOfMonth, fields[3]);
//设置第5位月
setMonths(this.months, fields[4]);
//设置第6位星期
setDays(this.daysOfWeek, replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8);
if (this.daysOfWeek.get(7)) {
// 星期天可以是0或者7 也就是说 Spring的星期是从0开始,1对应星期一,2对应星期2,依次类推
this.daysOfWeek.set(0);
this.daysOfWeek.clear(7);
}
}

示例

以下示例标示工作日内,每五秒执行一次任务。

@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomething() {
// something that should execute on weekdays only
}

关于Cron表达式

以下内容摘自oracle官网

而且cron一般被用在CronTrigger或者其子类org.quartz.Trigger。cron一般为6位,特殊情况下会是7位。相互直接以空格分割,允许的字符参阅下面的列表。

名称 必选项 允许值 允许特殊字符
Seconds Y 0-59 , - * /
Minutes Y 0-59 , - * /
Hours Y 0-23 , - * /
Day of month Y 1-31 , - * ? / L W C
Month Y 0-11 or JAN-DEC , - * /
Day of week Y 1-7 or SUN-SAT , - * ? / L C #
Year N empty or 1970-2099 , - * /

特殊字符含义说明

  • (*)星号:
    可以理解为每的意思,每秒,每分,每天,每月,每年…

  • (?)问号:问号只能出现在日期和星期这两个位置,表示这个位置的值不确定,每天3点执行,所以第六位星期的位置,我们是不需要关注的,就是不确定的值。同时:日期和星期是两个相互排斥的元素,通过问号来表明不指定值。比如,1月10日,比如是星期1,如果在星期的位置是另指定星期二,就前后冲突矛盾了。

  • (-)减号:表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12

  • (,)逗号:表达一个列表值,如在星期字段中使用“1,2,4”,则表示星期一,星期二,星期四

  • (/)斜杠:如:x/y,x是开始值,y是步长,比如在第一位(秒) 0/15就是,从0秒开始,每15秒,最后就是0,15,30,45,60 另:*/y,等同于0/y

  • (L):表示最后,比如表示每个月的最后一天等

  • (W):表示工作日,比如15W表示当月第15个工作日。
  • (C):表示日历, 比如2C,在月份中表示日历中的第二天,如果在星期上,则表示第一个星期一或者日历中的每一个星期一
  • (#):用于指定”第 n 个”XXX 天的月份。例如,值为”6 #3”在一天的星期字段中意味着”每月的第三个星期五”(第 6 天 = 周五和”#3”= 该月份的第 3 名)

cron示例

表达式 意义
0 0 12 * * ? 触发在 12 下午 (中午) 每一天
0 15 10?* * 触发在 10:15 上午每一天
0 15 10 * *? 触发在 10:15 上午每一天
0 15 10 * 触发在 10:15 上午每一天
0 15 10 * *?2005 触发在 10:15 上午在 2005 年期间的每一天
0 * 14 * *? 触发在 2 下午开始和结束于 2:59 下午,每一天每一分钟
0 0/5 14 * *? 触发在 2 下午开始和结束于 2:55 下午,每一天每隔 5 分钟
0 0/5 14,18 * * ? 触发在 2 下午开始和结束于 2:55 下午,每隔 5 分钟和触发在 6 下午开始和结束于 6:55 下午,每一天每隔 5 分钟
0 0 5 14 * *? 触发在 2 下午开始和结束于 2:05 下午,每一天每一分钟
0 10,44 14?3 WED 触发在 2:10 下午和 2:44 下午每周三在 3 月份。
0 15 10?* MON-FRI 触发在 10:15 上午,每个星期一、 星期二、 星期三、 星期四和星期五
0 15 10 15 * ? 触发在 10:15 上午每月 15 日
0 15 10 L *? 触发在 10:15 上午对每月的最后一天
0 15 10?* 6 L 触发在 10:15 上午对每月的最后一个星期五
0 15 10?* 6 L 触发在 10:15 上午对每月的最后一个星期五
0 15 10?* 6 L 2002-2005 触发在 10:15 上午在 2002年、 2003年、 2004 年和 2005 年每月每上星期五
0 15 10?* 6 #3 触发在 10:15 上午上每个月第三个星期五
0 0 12 1/5 *? 触发在 12 下午 (中午) 每隔 5 天每个月,每月的第一天开始。
0 11 11 11 11 ? 触发在 11:11 上午每 11 月 11 日。

最后

作者:ricky
QQ交流群:244930845