文章目录
Spring 中使用定时任务
在 Spring 中使用定时任务非常容易,步骤如下:
- 第一步在启动类加上
@EnableScheduling
注解,开启对定时任务的支持。
package com.springboot.chapter13;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling // 开启对定时任务的支持
public class Chapter13Application {
public static void main(String[] args) {
SpringApplication.run(Chapter13Application.class, args);
}
}
- 第二步在方法上加上
@Scheduled
注解,并配置配置项,编写定时逻辑。
package com.springboot.chapter13.task;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class MyTask {
int num = 1;
// 每隔 1s 执行一次
@Scheduled(fixedRate = 1000)
public void job1() {
System.out.println("敲了 " + num + " 个 BUG!");
num++;
}
}
注意:别忘了在
MyTask
类标注@Service
或@Component
等注解,将我们创建的MyTask
类注入到 Spring 容器中,这样 Spring 才会去执行定时任务。
- 启动项目,控制台打印信息如下:
上述中 @Scheduled
只是按照时间间隔执行,有时候需要指定更为具体的时间,例如,每天晚上 11:00 开始任务,或者一些任务在每周日执行。为了能够更为精确地指定任务执行的时间,所以有必要更为细致地研究 @Scheduled
的配置项。
@Scheduled 注解源码
@Target({
ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
String CRON_DISABLED = "-";
String cron() default "";
String zone() default "";
long fixedDelay() default -1L;
String fixedDelayString() default "";
long fixedRate() default -1L;
String fixedRateString() default "";
long initialDelay() default -1L;
String initialDelayString() default "";
}
@Scheduled 的配置项
配置项 | 类型 | 描述 |
---|---|---|
cron | String | 使用表达式的方式定义任务执行时间 |
zone | String | 可以通过它设定区域时间 |
fixedDelay | long | 表示从上一个任务完成开始到下一个任务开始的间隔,单位为毫秒 |
fixedDelayString | String | 与 fixedDelay 相同,只是使用字符串,这样可以使用 SpEL 来引入配置文件的配置 |
initialDelay | long | 在 Spring IoC 容器完成初始化后,首次任务执行延迟时间,单位为毫秒 |
initialDelayString | String | 与 initialDelay 相同,只是使用字符串,这样可以使用 SpEL 来引入配置文件的配置 |
fixedRate | long | 从上一个任务开始到下一个任务开始的间隔,单位为毫秒 |
fixedRateString | String | 与 fixedRate 相同,只是使用字符串,这样可以使用 SpEL 来引入配置文件的配置 |
上表中的配置项除了 cron 外都比较好理解,只有 cron 是可以通过表达式更为灵活地配置运行的方式。cron 有 6~7 个空格分隔的时间元素,按顺序依次是 “ 秒分时天月星期年 ”,其中年是一个可以不配置的元素,Spring 官方也给出了对应的图解,如下所示:
对 Spring 官网感兴趣的话,点击下方链接直达 Spring 定时任务模块。
小试牛刀:
0 0 0 ? * WED
这个配置表示每个星期三中午 0 点整。这个表达式需要注意的是其中的特殊字符,如 ?
和 *
,这里因为天和星期会产生定义上的冲突,所以往往会以通配符 ?
表示,它表示不指定值,而 *
则表示任意的月。除此以外还会有下表所示的其他通配符。
通配符含义
通配符 | 描述 |
---|---|
* | 表示任意值 |
? | 不指定值,用于处理天和日期配置的冲突 |
- | 指定时间区间 |
/ | 指定时间间隔执行 |
L | 最后的 |
# | 第几个 |
, | 列举多个项 |
cron 表达式举例
项目类型 | 描述 |
---|---|
0 0 0 * * ? | 每天 0 点整触发 |
0 15 23 ? * * | 每天 23:15 触发 |
0 15 0 * * ? | 每天 0:15 触发 |
0 15 10 * * ? | 每天早上 10:15 触发 |
0 30 10 * * ? 2018 | 2018 年的每天早上 10:30 触发 |
0 * 23 * * ? | 每天从 23 点开始到 23 点 59 分每分钟一次触发 |
0 0/3 23 * * ? | 每天从 23 点开始到 23:59 分结束每 3 min 一次触发 |
0 0/3 20,23 * * ? | 每天的 20 点至 20:59 和 23 点至 23:59 分两个时间段内每 3 min 一次触发 |
0 0-5 21 * * ? | 每天 21:00 至 21:05 每分钟一次触发 |
0 10,44 14 ? 3 WED | 3 月的每周三的 14:00 和 14:44 触发 |
0 0 23 ? * MON-FRI | 每周一到周五的 23:00 触发 |
0 30 23 ? * 5L 2017-2020 | 2017 年至 2020 年的每月最后一个周五的 23:30 触发 |
0 15 22 ? * 5#3 | 每月第三周周五的 22:15 触发 |
小工具 ->
在线 Cron 表达式生成器:https://cron.qqe2.com
下面再通过两个实例来巩固对定时任务的理解,代码如下:
// Spring IoC 容器初始化后,第一次延迟 3 秒 , 每隔 1 秒执行一次
@Scheduled(initialDelay = 3000,fixedRate = 1000)
public void job2() {
System.out.println("开始了!");
}
// 11:00 到 11:59 点每分钟执行一次
@Scheduled(cron = "0 * 11 * * ?")
public void job3() {
System.out.println("睡着了没?");
}
定时任务原理
参考文章链接:https://blog.csdn.net/weixin_34452850/article/details/81127569
如上文所述,我们可以通过 @EnableScheduling
注解开启对定时任务的支持,所以我们先从 @EnableScheduling
注解开始说起。
@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({
SchedulingConfiguration.class})
@Documented
public @interface EnableScheduling {
}
可以看到,@EnableScheduling
注解的主要功能就是通过 @Import
注解导入了 SchedulingConfiguration 配置类,@Import
注解是 Spring 提供的导入注解,可以将一个配置类或者普通的一个类初始化到 Spring 容器中,具体使用可以参考 https://blog.csdn.net/u010502101/article/details/78760032,这里不再赘述。现在我们来看 SchedulingConfiguration 配置类。
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
// 向 IOC 容器中注册一个 ScheduledAnnotationBeanPostProcessor 实例
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor