[Java实战]Spring Boot 定时任务(十五)
一、定时任务的应用场景
- 数据同步:每日凌晨同步第三方数据
- 状态检查:每5分钟扫描订单超时未支付
- 资源清理:每小时清理临时文件
- 报表生成:每月1号生成财务统计报表
- 通知推送:每天9点发送生日祝福短信
二、Spring Boot 定时任务的 3 种实现方式
1. 基于 @Scheduled
注解(推荐)
核心注解:
@EnableScheduling
:启动类启用定时任务@Scheduled
:定义任务执行规则
示例代码:
java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class OrderTimeoutTask {
// 每5分钟执行(支持cron、fixedRate、fixedDelay)
@Scheduled(cron = "0 */5 * * * ?")
public void checkUnpaidOrders() {
// 查询超时订单逻辑
System.out.println("执行订单超时检查: " + new Date());
}
// 固定间隔3秒(上次结束后间隔)
@Scheduled(fixedDelay = 3000)
public void cleanupTempFiles() {
// 清理临时文件
}
// 固定频率2秒(无视执行时长)
@Scheduled(fixedRate = 2000)
public void heartbeatCheck() {
// 服务心跳检测
}
}
Cron 表达式详解:
字段 | 秒 | 分 | 时 | 日 | 月 | 周 | 年(可选) |
---|---|---|---|---|---|---|---|
值 | 0-59 | 0-59 | 0-23 | 1-31 | 1-12 | 1-7 (或 SUN-SAT) | 1970-2099 |
常用表达式示例:
0 0 2 * * ?
:每天凌晨2点0 0/30 9-17 * * MON-FRI
:工作日9点到17点每30分钟0 15 10 L * ?
:每月最后一天10:15

2. 动态定时任务(数据库驱动)
适用场景 :需要运行时调整执行周期
实现步骤:
- 创建任务配置表
sql
CREATE TABLE task_config (
id BIGINT PRIMARY KEY,
task_name VARCHAR(50) UNIQUE,
cron_expression VARCHAR(20),
enabled BOOLEAN
);
- 实现动态任务注册
java
@Component
public class DynamicTask implements SchedulingConfigurer {
@Autowired
private TaskConfigRepository repository;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
List<TaskConfig> tasks = repository.findEnabledTasks();
tasks.forEach(config ->
taskRegistrar.addCronTask(
() -> executeTask(config.getTaskName()),
config.getCronExpression()
)
);
}
private void executeTask(String taskName) {
// 根据任务名称执行逻辑
}
}
3. 整合 Quartz 框架(分布式支持)
优势 :支持持久化、集群、动态调度
实现步骤:
- 添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
- 定义 Job 类
java
public class EmailJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) {
// 发送邮件逻辑
}
}
- 配置触发器与调度器
java
@Configuration
public class QuartzConfig {
@Bean
public JobDetail emailJobDetail() {
return JobBuilder.newJob(EmailJob.class)
.withIdentity("emailJob")
.storeDurably()
.build();
}
@Bean
public Trigger emailJobTrigger() {
CronScheduleBuilder schedule = CronScheduleBuilder.cronSchedule("0 0 9 * * ?");
return TriggerBuilder.newTrigger()
.forJob(emailJobDetail())
.withIdentity("emailTrigger")
.withSchedule(schedule)
.build();
}
}
三、高级配置与最佳实践
1. 线程池优化
默认问题 :所有任务共享单线程
自定义线程池:
java
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar registrar) {
ThreadPoolTaskScheduler threadPool = new ThreadPoolTaskScheduler();
threadPool.setPoolSize(5);
threadPool.setThreadNamePrefix("scheduled-task-");
threadPool.initialize();
registrar.setTaskScheduler(threadPool);
}
}
2. 分布式锁防重复执行
Redisson 实现示例:
java
@Scheduled(cron = "0 0 2 * * ?")
public void generateDailyReport() {
RLock lock = redissonClient.getLock("reportLock");
try {
if (lock.tryLock(0, 30, TimeUnit.SECONDS)) {
// 执行报表生成
}
} finally {
lock.unlock();
}
}
3. 任务监控与健康检查
暴露执行指标:
java
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("application", "task-monitor");
}
// 在任务中记录指标
@Scheduled(fixedRate = 5000)
public void recordMetrics() {
Metrics.counter("tasks.executed").increment();
}
四、常见问题排查
-
任务未执行
- 检查是否添加
@EnableScheduling
- 确认
@Component
或@Service
注解生效 - 查看日志中是否有异常抛出
- 检查是否添加
-
任务重复执行(分布式环境)
- 使用数据库乐观锁或 Redis 分布式锁
- 开启 Quartz 集群模式
-
任务执行时间过长
- 配置
@Async
异步执行
java@Async("taskExecutor") @Scheduled(fixedRate = 5000) public void processData() { /* 长时间任务 */ }
- 配置
五、Spring Boot 定时任务 vs 其他方案
方案 | 优点 | 缺点 |
---|---|---|
@Scheduled | 简单易用、零配置 | 不支持动态调整、无持久化 |
Quartz | 功能强大、支持分布式 | 配置复杂、依赖数据库 |
XXL-JOB | 可视化调度、报警完善 | 需要独立部署调度中心 |
Elastic Job | 弹性扩容、数据分片 | 学习成本高 |
六、总结
Spring Boot 通过 @Scheduled
提供了轻量级定时任务支持,适合单机简单场景。对于复杂需求,可结合 Quartz 或选用分布式任务调度框架(如 XXL-JOB)。关键是根据业务规模选择合适方案,并注意线程安全、幂等性、可观测性等生产级要求。
附录:
希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!