Spring Task
在企业级开发中,我们经常需要处理一些“定时”或“周期性”的任务,比如每天凌晨生成报表、每隔 1 小时清理一次缓存或者每分钟检查一次支付状态。Spring Task 就是为此设计的轻量级解决方案。
1. 什么是 Spring Task?
Spring Task 是 Spring Framework 自 3.0 版本起引入的任务调度模块。它提供了一套简单、注解驱动的方式来实现定时任务,无需引入像 Quartz 这样复杂的外部框架,就能满足绝大多数单机应用的调度需求。
核心优势:
- 配置简单:只需几个注解即可搞定,不需要复杂的 XML 或对象配置。
- 无需依赖:作为 Spring 的核心模块,不需要引入额外的 jar 包。
- 支持 Cron 表达式:支持非常灵活的时间配置。
2. 核心注解
要让 Spring Task 跑起来,你只需要记住两个关键注解:
@EnableScheduling:放在配置类或启动类上,表示开启定时任务功能。@Scheduled:放在具体的方法上,定义该任务的执行触发时机。
3. 任务触发方式
在 @Scheduled 注解中,有三种常见的执行频率设置方式:
A. fixedRate (固定速率)
任务开始执行后,每隔指定时间执行一次。
例子:
@Scheduled(fixedRate = 5000)—— 每 5 秒执行一次,不管上一次任务是否结束。
B. fixedDelay (固定延迟)
上一次任务结束后,经过指定时间再执行下一次。
例子:
@Scheduled(fixedDelay = 5000)—— 如果任务跑了 10 秒,结束后再等 5 秒才跑下一次。
C. cron (Cron 表达式)
最强大的方式,可以指定非常具体的时间点。注意: “日” 和 “周” 两个字段不能同时指定具体数值,规定一个,另外一个就写"?"。
语法结构:
[秒] [分] [时] [日] [月] [周]例子:
@Scheduled(cron = "0 0 2 * * ?")—— 每天凌晨 2:00 执行。
4. 快速上手代码示例
下面是一个简单的实现逻辑:
java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class MyStaticTask {
// 1. 每隔 10 秒执行一次
@Scheduled(fixedRate = 10000)
public void reportCurrentTime() {
System.out.println("现在时间:" + LocalDateTime.now());
}
// 2. 每天凌晨 1 点清理日志
@Scheduled(cron = "0 0 1 * * ?")
public void cleanLogs() {
System.out.println("清理日志任务开始...");
}
}5. 注意事项与局限性
虽然 Spring Task 很好用,但在使用时有两点需要注意:
- 默认单线程执行:Spring Task 默认使用单线程池。这意味着如果你的任务 A 卡住了,任务 B 即使到了时间也无法执行。如果你有大量并发任务,建议配置
TaskScheduler线程池。 - 不支持分布式:Spring Task 是内存级的任务调度。如果你的应用部署了多台服务器(集群),每台机器都会在同一时间跑同一个任务。
- 解决方法:如果是分布式环境,通常需要配合 Redis 分布式锁,或者改用 ShedLock、XXL-JOB 等分布式调度平台。
- Spring 坑:定时任务方法必须是
public的,且所在的类必须被@Component或@Service扫描到,否则任务根本不会被触发。