springboot定时任务的三种基本实现方式
前言
又是一年的年底,时间过得好快,项目都没做几个,两手空空,钱包空空一年就这样过去了。才发现好久没在这里发文章了,今天就水一篇 SpringBoot 的定时任务来弥补一下博主
。话不多说,一共有三种⬇️
- 第一种:基于注解 (@Scheduled)的方式
- 第二种:基于接口 (SchedulingConfigurer)
- 第三种:基于注解设定多线程定时任务
一、基于注解 (@Scheduled)的方式
这一种方式是 SpringBoot 自带的定时器(基于cron表达式),无需引入第三方jar,直接一个注解在public的方法上即可触发,但前提是类需要启用定时@EnableScheduling 下面使用一个简单的例子
@Component
@EnableScheduling
@Slf4j
public class TaskTest {
@Scheduled(cron = "*/5 * * * * ?")
public void task1(){
log.info("hello world!");
}
}以上例子会每5秒输出 hello world!

@Scheduled 除过cron还有三种方式:fixedRate,fixedDelay,initialDelay
fixedRate 控制方法执行的间隔时间,是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次。
@Component
@EnableScheduling
@Slf4j
public class TaskTest {
@Scheduled(fixedRate = 5000)
public void task1(){
log.info("task1");
}
@Scheduled(fixedRate = 6000)
public void task2(){
log.info("task2");
}
}
fixedDelay 是以上一次结束时间为基准的延时执行,用法和fixedRate一致
initialDelay 表示在容器启动后,延迟x秒后再执行一次定时器。
@Component
@EnableScheduling
@Slf4j
public class TaskTest {
@Scheduled(initialDelay = 5000, fixedDelay = 5000)
public void task1(){
log.info("initialDelay");
}
}以上会在容器启动后延迟5秒后输出,并在每5秒输出

Cron表达式解释
结构
cron表达式是一个字符串,分为6或7个域,每两个域之间用空格分隔,
其语法格式为:"秒域、分域、时域、日域、月域、周域、年域"
取值范围
| 域 | 取值 | 符号(常用) |
|---|---|---|
| 秒 | 0~59的整数 | * - , / |
| 分 | 0~59的整数 | * - , / |
| 时 | 0~23的整数 | * - , / |
| 日 | 1~31的整数 | * - , / ? L |
| 月 | 1~12的整数或英文 JAN~DEC | * - , / |
| 周 | 1~7的整数或英文SUN~SAT | * - , / ? L # |
| 年 | 1970~2099的整数 | * - , / |
一些常用的cron
可直接复制使用,自己微调一下就好了![[辣眼睛]](https://bs.oxoxtech.com/frontSystem/emoji/辣眼睛.png#emoji)
| Cron 表达式 | 含义 |
|---|---|
| */5 * * * * ? | 每隔5秒钟执行一次 |
| 0 * /1 * * * ? | 每隔1分钟执行一次 |
| 0 0 1 * * ? | 每天1点执行一次 |
| 0 55 23 * * ? | 每天23点55分执行一次 |
| 0 0 23 L * ? | 每月最后一天23点执行一次 |
| 0 0 8 ? * L | 每周六8点执行一次 |
| 0 0 */2 ? * 6L | 每月最后一个周五,每隔2小时执行一次 |
| 0 15 10 ? * 5#3 | 每月的第三个星期五上午10:15执行一次 |
| 0 0-5 14 * * ? | 在每天下午2点到下午2:05期间的每1分钟执行 |
| 0 15 10 ? * 2-6 | 表示周一到周五每天上午10:15执行 |
| 0 15 10 ? * 6L | 每个月的最后一个星期五上午10:15执行 |
| 0 0 10,14,16 * * ? | 每天上午10点,下午2点,4点执行一次 |
| 0 0/30 9-17 * * ? | 朝九晚五工作时间内每半小时执行一次 |
| 0 0 12 ? * 4 | 每个星期三中午12点执行一次 |
| 0 10,44 14 ? 3 4 | 每年三月的星期三的下午2:10和2:44各执行一次 |
| 0 15 10 ? * 6#3 | 每月的第三个星期五上午10:15执行一次 |
| 0 30 2 1 * ? | 每月一日凌晨2点30执行一次 |
| 10,20 * * * * ? | 每分钟的第10秒与第20秒都会执行 |
| 0 0 0 ? * 6#2 | 每月的第2个星期的周5,凌晨执行 |
二、基于接口 (SchedulingConfigurer)
使用 @Scheduled 注解很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,只适用测试环境和一些固定的场景。那么为了达到实时生效的效果,可以使用接口来完成定时任务,统一将定时器信息存放在数据库中。
本质就是利用数据库将cron表达式存储下来,在启动定时器的时候查询出相应的cron再放入定时器中执行,由于篇幅不易太长,下面免去数据库操作部分的解释,直接给出代码示例:
@Component
@EnableScheduling
@Slf4j
public class TaskTest implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(this::task, t ->{
// todo 假设此处的cron是从数据库查询出来的
String cron = "*/5 * * * * ?";
return new CronTrigger(cron).nextExecutionTime(t);
});
}
private void task(){
log.info("Interface-based scheduled tasks");
}
}以上代码本质就是使用一个触发器触发一个cron任务,这个任务可以是你的任意方法。

三、基于注解设定多线程定时任务
前面讲到了 @Scheduled 执行周期任务会受到上次一个任务的执行时间阻塞影响,那么可以开启多线程执行周期任务。
@Component
@EnableScheduling
@EnableAsync
@Slf4j
public class TaskTest {
@Async
@Scheduled(fixedDelay = 5000)
public void task1() throws InterruptedException {
log.info("task1,{}",Thread.currentThread().getName());
Thread.sleep(3000);
}
@Async
@Scheduled(fixedDelay = 3000)
public void task2(){
log.info("task2,{}",Thread.currentThread().getName());
}
}其实用法都是一样的,只是多了两个注解,一个是开启异步 @EnableAsync ,一个是方法异步注解 @Async

最后
以上就简单介绍了一下Spring Boot的三种定时器的用法,不过,正常使用定时任务的以上三种方式足够你实现业务上的问题,还有更多其他的用法由于篇幅问题就不再延伸,希望广大网友可以评论区指出
。