[Java实战]Spring Boot 定时任务(十五)

[Java实战]Spring Boot 定时任务(十五)

一、定时任务的应用场景
  1. 数据同步:每日凌晨同步第三方数据
  2. 状态检查:每5分钟扫描订单超时未支付
  3. 资源清理:每小时清理临时文件
  4. 报表生成:每月1号生成财务统计报表
  5. 通知推送:每天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. 动态定时任务(数据库驱动)

适用场景 :需要运行时调整执行周期
实现步骤

  1. 创建任务配置表
sql 复制代码
CREATE TABLE task_config (
    id BIGINT PRIMARY KEY,
    task_name VARCHAR(50) UNIQUE,
    cron_expression VARCHAR(20),
    enabled BOOLEAN
);
  1. 实现动态任务注册
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 框架(分布式支持)

优势 :支持持久化、集群、动态调度
实现步骤

  1. 添加依赖
xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
  1. 定义 Job 类
java 复制代码
public class EmailJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) {
        // 发送邮件逻辑
    }
}
  1. 配置触发器与调度器
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();
}
四、常见问题排查
  1. 任务未执行

    • 检查是否添加 @EnableScheduling
    • 确认 @Component@Service 注解生效
    • 查看日志中是否有异常抛出
  2. 任务重复执行(分布式环境)

    • 使用数据库乐观锁或 Redis 分布式锁
    • 开启 Quartz 集群模式
  3. 任务执行时间过长

    • 配置 @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)。关键是根据业务规模选择合适方案,并注意线程安全、幂等性、可观测性等生产级要求。

附录

希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!

相关推荐
bing_15820 分钟前
Spring MVC 中Model, ModelMap, ModelAndView 之间有什么关系和区别?
java·spring·mvc
2685725938 分钟前
JVM 监控
java·开发语言·jvm
promise52439 分钟前
JVM之jcmd命令详解
java·linux·运维·服务器·jvm·bash·jcmd
曼岛_1 小时前
[Java实战]Spring Boot 静态资源配置(十三)
java·开发语言·spring boot
篱笆院的狗1 小时前
MySQL 中如何进行 SQL 调优?
java·sql·mysql
老朋友此林1 小时前
MiniMind:3块钱成本 + 2小时!训练自己的0.02B的大模型。minimind源码解读、MOE架构
人工智能·python·nlp
随风奔跑的十八岁1 小时前
java 破解aspose.words 18.6 使用
java·linux·word转pdf·aspose-words
居然是阿宋2 小时前
C语言的中断 vs Java/Kotlin的异常:底层机制与高级抽象的对比
java·c语言·kotlin
sco52822 小时前
SpringBoot 自动装配原理 & 自定义一个 starter
java·spring boot·后端
曼岛_2 小时前
[Java实战]Spring Boot 快速配置 HTTPS 并实现 HTTP 自动跳转(八)
java·spring boot·http