SpringBoot定时任务@Scheduled基础与动态定时详解
作者:SoftHope
时间:2026-06-27
来源:互联网
浏览:1
SpringBoot定时任务提供静态@Scheduled与动态SchedulingConfigurer两种方案。静态支持fixedRate、fixedDelay、cron表达式,默认单线程易阻塞。动态任务可将cron存于数据库,运行时修改无需重启。通过配置线程池或@Async实现并行,适用于订单超时关单、日志清理等场景。
在后台开发中,定时任务几乎是个绕不开的基础设施——订单超时自动关单、优惠券定时失效、日志和垃圾文件定期清理、统计报表在凌晨悄然生成、缓存定时刷新、分布式数据同步……但凡一个中后台项目,或多或少都会用到。

SpringBoot 自带的定时任务方案开箱即用,不需要额外引入 Quartz 或 XXL-Job 这样的中间件,轻量、无依赖,对于大部分场景已经足够应付。
## 一、定时任务整体架构与适用场景
### 核心分类
1. **静态定时任务**
基于 `@Scheduled` 实现,规则写在代码或配置文件里,启动后就不能改了。好处是简单、零依赖、开发极快;缺点是不灵活,而且默认单线程容易阻塞。
2. **动态定时任务**
基于 `SchedulingConfigurer` + `Trigger` 实现,运行时可以修改 cron、启停任务,不需要重启服务。灵活度很高,适合需要运营后台动态配置的场景,缺点是代码稍微复杂一些,需要自己维护任务状态。
3. **分布式定时任务**
比如 Quartz、XXL-Job、Elastic-Job,主要解决集群环境下多个节点重复执行的问题。本文重点讲 Spring 内置方案,分布式只做对比参考。
### 典型业务场景
- 每日凌晨 2:00 清理 7 天前的日志、生成日账单
- 下单 30 分钟未支付自动取消
- 定时检查服务器状态、接口健康度
- 运营在后台修改任务执行时间
## 二、@Scheduled 静态定时任务
### 1. 开启定时任务总开关
启动类加上 `@EnableScheduling`,否则定时任务不会生效:
```ja va
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling // 开启 Spring 定时任务
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
- 如 Quartz、XXL-Job、Elastic-Job
- 解决集群下任务重复执行问题
- 本文重点讲 Spring 内置方案,分布式仅作对比
- 固定周期:每 5 分钟刷新一次统计数据
- 每日凌晨:2:00 清理 7 天前日志、生成日账单
- 超时任务:下单 30 分钟未支付自动取消
- 周期巡检:定时检查服务器状态、接口健康度
- 动态配置:运营在后台修改任务执行时间
### 2. @Scheduled 三大核心参数
`@Scheduled` 支持 3 种触发规则,**不可同时混用**,只能选其一。
#### (1) fixedRate:固定频率执行
含义:**从上一次任务开始时间计算**,每隔指定毫秒执行一次。如果任务执行时间比间隔长,任务会排队,不会并行。
```ja va
// 每 5 秒执行一次(从上一次启动时算)
@Scheduled(fixedRate = 5000)
public void taskFixedRate() {
System.out.println("fixedRate 每5秒执行:" + LocalDateTime.now());
}
```
#### (2) fixedDelay:固定延迟执行
含义:**从上一次任务执行结束时间计算**,等待指定毫秒再执行。保证任务串行,不会重叠。
```ja va
// 上一次执行完,等 5 秒再执行
@Scheduled(fixedDelay = 5000)
public void taskFixedDelay() {
System.out.println("fixedDelay 执行完延迟5秒:" + LocalDateTime.now());
}
```
#### (3) cron:Cron 表达式
支持秒级复杂规则:每天、每周、每月、指定时分秒。格式:`秒 分 时 日 月 周`。
```ja va
// 每 10 秒执行一次
@Scheduled(cron = "0/10 * * * * ?")
public void taskCron() {
System.out.println("cron 每10秒执行:" + LocalDateTime.now());
}
```
### 3. 初始延迟:initialDelay
项目启动后,**不立即执行**,等待一段时间再开始:
```ja va
// 项目启动延迟 3 秒后,每 5 秒执行一次
@Scheduled(initialDelay = 3000, fixedRate = 5000)
public void taskInitialDelay() {
System.out.println("启动延迟3秒后执行");
}
```
### 4. Cron 表达式完整详解
语法结构:
```
秒(0-59) 分(0-59) 时(0-23) 日(1-31) 月(1-12) 周(1-7,1=周日,7=周六)
```
常用符号:
- `*`:每一秒/每一分/每一时刻
- `?`:不指定(日和周互斥,必须有一个为 ?)
- `/`:步长,如 `0/5` 表示从 0 开始,每 5 单位
- `-`:范围,如 `10-20` 表示 10 到 20
- `,`:枚举,如 `1,3,5` 表示 1、3、5
示例:
```ja va
"0 0 2 * * ?" = 每天凌晨 2 点
"0 0 0 * * ?" = 每天午夜 0 点
"0 0/5 * * * ?" = 每 5 分钟
"0 0 12 * * ?" = 每天中午 12 点
"0 0 8 ? * MON-FRI" = 工作日早上 8 点
"0 0 0 1 * ?" = 每月 1 号零点
"0/1 * * * * ?" = 每秒执行
```
### 5. 从配置文件读取
硬编码 cron 不利于维护,推荐放到 `application.yml`:
```yaml
# 定时任务配置
scheduled:
task1:
cron: "0/5 * * * * ?"
task2:
fixed-rate: 10000
initial-delay: 5000
```
使用方式:
```ja va
@Scheduled(cron = "${scheduled.task1.cron}")
public void configTask() {
System.out.println("从yml读取cron执行");
}
```
## 三、解决单线程阻塞问题
Spring 定时任务**默认是单线程**的,多个任务会排队,一个卡死全部卡住。
### 1. 配置定时任务线程池
```ja va
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@Configuration
@EnableScheduling
public class ScheduledThreadPoolConfig {
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10); // 核心线程数,根据任务数量设置
scheduler.setThreadNamePrefix("scheduled-task-"); // 线程名称前缀,方便日志排查
scheduler.setWaitForTasksToCompleteOnShutdown(true); // 等待任务完成再关闭
scheduler.setAwaitTerminationSeconds(60); // 关闭最大等待时间
scheduler.initialize();
return scheduler;
}
}
```
配置之后,多个任务可以**并行执行**,互不阻塞。
## 四、异步 + 定时(@Async + @Scheduled)
让定时任务**异步执行**,不占用调度线程,进一步提升稳定性。
### 1. 开启异步
启动类加 `@EnableAsync`:
```ja va
@SpringBootApplication
@EnableScheduling
@EnableAsync // 开启异步
public class Application {}
```
### 2. 异步定时任务
```ja va
@Component
public class AsyncScheduleTask {
@Async
@Scheduled(cron = "0/5 * * * * ?")
public void asyncTask() {
System.out.println("异步定时任务执行:" + Thread.currentThread().getName());
}
}
```
优点很明显:任务执行耗时不影响调度,异常也不会导致调度线程崩溃。
## 五、动态定时任务
`@Scheduled` 启动后就不能改 cron,**运营后台配置、动态调整**必须用动态定时方案。
### 1. 核心原理
- 实现 `SchedulingConfigurer`
- 重写 `configureTasks` 注册任务
- 使用 `CronTrigger` 动态读取最新 cron
- 把 cron 存在 DB/Redis/Nacos 中,实现真正可配置
### 2. 完整动态定时任务实现
```ja va
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import ja va.time.LocalDateTime;
import ja va.util.concurrent.atomic.AtomicBoolean;
@Slf4j
@Configuration
public class DynamicScheduleConfig implements SchedulingConfigurer {
// 动态 cron(真实项目从数据库/Redis读取)
private String cron = "0/5 * * * * ?";
// 任务启停开关
private final AtomicBoolean taskEnabled = new AtomicBoolean(true);
// 外部修改 cron
public void setCron(String cron) {
this.cron = cron;
log.info("动态修改cron成功:{}", cron);
}
// 启停任务
public void setTaskEnabled(boolean enabled) {
this.taskEnabled.set(enabled);
log.info("任务状态已修改:{}", enabled ? "开启" : "关闭");
}
@Override
public void configureTasks(ScheduledTaskRegistrar registrar) {
registrar.addTriggerTask(
// 任务业务逻辑
() -> {
if (!taskEnabled.get()) {
log.info("任务已关闭,跳过执行");
return;
}
log.info("动态定时任务执行:{}", LocalDateTime.now());
// 执行业务逻辑...
},
// 动态触发器:每次执行前重新获取cron
triggerContext -> {
CronTrigger cronTrigger = new CronTrigger(cron);
return cronTrigger.nextExecutionTime(triggerContext);
}
);
}
}
```
### 3. 提供接口动态控制
```ja va
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/schedule")
public class ScheduleController {
@Autowired
private DynamicScheduleConfig dynamicScheduleConfig;
// 动态修改 cron
@GetMapping("/updateCron")
public String updateCron(@RequestParam String cron) {
try {
dynamicScheduleConfig.setCron(cron);
return "修改成功,新cron:" + cron;
} catch (Exception e) {
return "cron 格式非法:" + e.getMessage();
}
}
// 开启/关闭任务
@GetMapping("/enable")
public String enableTask(@RequestParam boolean enabled) {
dynamicScheduleConfig.setTaskEnabled(enabled);
return "任务已" + (enabled ? "开启" : "关闭");
}
}
```
测试接口:
```bash
# 修改为每10秒执行一次
http://localhost:8080/schedule/updateCron?cron=0/10 * * * * ?
# 关闭任务
http://localhost:8080/schedule/enable?enabled=false
```
**无需重启,立即生效!**
## 六、定时任务异常处理
定时任务一旦抛异常且未捕获,会导致**后续调度失效**,必须做异常防护。
### 1. 统一 try-catch 防护
```ja va
@Scheduled(cron = "${scheduled.task1.cron}")
public void safeTask() {
try {
// 业务逻辑
System.out.println("任务执行");
} catch (Exception e) {
// 记录日志 + 告警
log.error("定时任务执行异常", e);
}
}
```
### 2. 全局异常捕获
结合 AOP 或全局异常切面统一捕获,避免每个任务里都写 try-catch。
## 七、静态 vs 动态 方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|------|------|------|----------|
| @Scheduled 静态 | 极简、零依赖、上手快 | 不可修改、单线程阻塞 | 固定周期、不常变更的任务 |
| 动态定时(Trigger) | 运行可改、可启停、灵活配置 | 代码稍复杂 | 运营后台配置、动态调整、多环境适配 |
| 异步定时 | 不阻塞调度、高可用 | 需注意线程安全、事务 | 耗时任务、批量处理任务 |
## 八、注意事项
1. **禁止在定时任务中写超大耗时操作**
超过 1 分钟的任务建议丢 MQ 或线程池异步处理。
2. **集群部署必须防止重复执行**
Spring 内置定时不支持分布式,集群下会多节点同时执行。解决方案包括数据库乐观锁、Redis 分布式锁(Redisson),或者直接用 XXL-Job 这类分布式定时任务。
3. **关键任务必须加监控告警**
任务执行失败、超时,要通过邮件、钉钉或企业微信及时告警。
4. **cron 尽量避开高峰整点**
大量任务都挤在 0 点执行,瞬间压力很大,建议错峰执行。
5. **日志必须清晰**
记录任务的开始/结束时间、耗时、异常信息,方便日后排查。
## 九、总结
- `@EnableScheduling` 是定时任务的开关,缺一不可;
- `@Scheduled` 支持 `fixedRate`、`fixedDelay`、`cron`,生产环境优先用配置化的 cron;
- 多任务必须配置**线程池**,避免单线程阻塞;
- 耗时任务用 `@Async` 异步化,提升系统稳定性;
- 动态定时基于 `SchedulingConfigurer`,可以实现运行时修改、启停;
- 生产务必做好**异常捕获、监控告警、分布式锁防重复**。
本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
苹果折叠屏iPhone是翻盖还是对折形态
2026-09-14 13:33
PDF转Word的4种方法及结果核对步骤
2026-09-09 06:00
速腾聚创自研SPAD-SoC芯片交付破50万颗,MARS基地实现8秒下线一台激光雷达
2026-09-08 17:42
TECNO Camon Slim 5G发布:6.39mm机身与6000mAh电池规格解析
2026-09-08 17:04
小米 18 Fold 暖金白图赏:中折叠形态与核心规格解析
2026-09-08 16:50
热门文章
更多
精品专题
更多
Mac软件
更多
WINDOWS
更多
Windows 10
Windows
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式
Windows/macOS/Linux
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















