Spring进阶特性 任务调度(@Scheduled)

Spring 任务调度(Task Scheduling)是企业级项目中真正意义上的“进阶必备特性”。
从最简单的 @Scheduled 到生产级分布式定时任务,几乎所有后台系统都离不开它。

以下是 2025 年最新的、最地道的 Spring Boot 3.x(Spring 6 + JDK 17+)任务调度全攻略。

1. 核心对比总览(2025 最新推荐)

方式是否支持集群分布式是否支持动态增删改查是否支持持久化是否支持延迟/周期任务推荐场景
@Scheduled + 单机不支持只能重启不支持支持简单项目、小型服务
@Scheduled + ShedLock支持(轻量锁)只能重启依赖数据库/Redis支持中型项目,快速分布式化
Spring Boot 3 自带 Scheduling不支持支持(动态任务)不支持支持需要动态开关、修改cron的任务
Quartz Scheduler(官方推荐)支持支持(完全动态+UI)支持(数据库)支持所有类型大中型、核心业务、银行级定时任务
XXL-JOB / ElasticJob / PowerJob支持支持(带管理后台)支持支持超大型分布式系统、需要任务分片、失败告警等

2. 基础用法:@Scheduled(90% 项目够用)

@Component
@EnableScheduling                    // 主类或配置类上必须加
public class SimpleScheduledTasks {

    // 固定延迟:上一次执行完成时间点之后 5 秒再执行
    @Scheduled(fixedDelay = 5000)
    public void reportCurrentTime() {
        System.out.println("固定延迟:" + LocalDateTime.now());
    }

    // 固定频率:上一次开始时间点之后 5 秒执行(即使上一次还没执行完)
    @Scheduled(fixedRate = 5000)
    public void fixedRateTask() throws InterruptedException {
        Thread.sleep(8000);
        System.out.println("固定频率:" + LocalDateTime.now());
    }

    // Cron 表达式(最常用)
    @Scheduled(cron = "0 */2 * * * ?")    // 每2分钟的第0秒执行
    public void cronTask() {
        System.out.println("Cron任务:" + LocalDateTime.now());
    }

    // 启动后延迟 10 秒,然后每 5 秒执行一次
    @Scheduled(initialDelay = 10000, fixedRate = 5000)
    public void withInitialDelay() { ... }
}

Cron 表达式速查(2025 版)

秒 分 时 日 月 星期 年(可选)
0 0 2 * * ? 每天凌晨2点
0 0/30 9-17 * * ? 工作日9点到17点每30分钟
0 0 12 ? * MON-FRI 每周一到周五中午12点
0 15 10 L * ? 每月最后一天10:15

### 3. 生产必备:分布式锁防止重复执行(推荐 ShedLock)

集群部署后,同一个 `@Scheduled` 会在每台机器上都执行一次,必须加锁!

xml

net.javacrumbs.shedlock shedlock-spring 5.10.2
net.javacrumbs.shedlock shedlock-provider-jdbc-template 5.10.2

java
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = “PT30M”) // 最多锁30分钟
public class ShedLockConfig {

@Bean
public LockProvider lockProvider(DataSource dataSource) {
    return new JdbcTemplateLockProvider(
        JdbcTemplateLockProvider.Configuration.builder()
            .withJdbcTemplate(new JdbcTemplate(dataSource))
            .usingDbTime() // 使用数据库时间,防止服务器时间不同步
            .build()
    );
}

}

使用方式:

java
@Scheduled(cron = “0 0 1 * * ?”)
@SchedulerLock(name = “dailyClearTask”, lockAtLeastFor = “PT10M”, lockAtMostFor = “PT12H”)
public void dailyClear() {
// 只有拿到锁的节点才会执行
}

### 4. 动态定时任务(无需重启即可增删改cron)

Spring Boot 3 原生支持动态任务(超级好用!

java
@Service
public class DynamicTaskService {

private final TaskScheduler taskScheduler;
private ScheduledFuture<?> future;

public DynamicTaskService(TaskScheduler taskScheduler) {
    this.taskScheduler = taskScheduler;
}

// 启动一个可动态修改的定时任务
public void startCronTask(String cron) {
    stopTask(); // 先停掉旧的

    this.future = taskScheduler.schedule(
        () -> System.out.println("动态任务执行:" + LocalDateTime.now()),
        new CronTrigger(cron)
    );
}

public void stopTask() {
    if (future != null) {
        future.cancel(true);
    }
}

// 对外提供修改接口
@PostMapping("/task/cron")
public R<Void> updateCron(@RequestBody String newCron) {
    startCronTask(newCron);
    return R.ok();
}

}

### 5. 终极方案:Quartz(银行、核心系统标配)

yaml

application.yml

spring:
quartz:
job-store-type: jdbc # 持久化到数据库
jdbc:
initialize-schema: always # 自动建表
properties:
org:
quartz:
scheduler:
instanceId: AUTO
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
isClustered: true # 开启集群
threadPool:
threadCount: 25

核心代码:

java
@Service
public class QuartzService {

private final Scheduler scheduler;

// 动态添加任务
public void addJob(String jobName, String cron) throws SchedulerException {
    JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
        .withIdentity(jobName)
        .storeDurably()
        .build();

    Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity(jobName + "_trigger")
        .withSchedule(CronScheduleBuilder.cronSchedule(cron))
        .build();

    scheduler.scheduleJob(jobDetail, trigger);
}

// 支持暂停、恢复、删除、立即触发等

}
“`

6. 推荐架构(2025 真实生产实践)

项目规模推荐方案说明
小项目/个人项目@Scheduled + @EnableScheduling够用,简单
中型项目(3~10台服务器)@Scheduled + ShedLock5分钟搞定分布式,零侵入性
大中型项目(10+服务器)原生 Quartz(JDBC 集群模式)官方、稳定、支持任务持久化、失败重试、MISFIRE策略
超大规模/互联网公司XXL-JOB 或 PowerJob自带管理后台、分片广播、失败告警、路由策略、滚动日志等

7. 常见坑 & 最佳实践

  1. 永远不要在 @Scheduled 方法里抛出未捕获异常 → 会导致定时任务线程死亡,后续不再执行!
  2. 长时间任务一定要用 fixedDelay,不要用 fixedRate
  3. 业务代码要幂等!定时任务可能因为 MISFIRE 重试多次。
  4. 生产环境一定要加监控:任务执行耗时、成功率、最后执行时间。
  5. 使用 @Async + @Scheduled 时注意线程池不要被打满。

需要我直接给你一个完整的生产级模板项目吗?包含:

  • ShedLock + MySQL 分布式锁
  • 动态任务管理接口
  • Quartz 集群版
  • 统一任务日志表 + 监控告警

直接说一声,我发你 GitHub 仓库地址。

文章已创建 3070

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部