当前位置: 首页 > news >正文

Spring Scheduler定时任务实战:从零掌握任务调度

前言

在日常开发中,我们经常需要处理定时任务:每天凌晨的数据同步、每小时的统计报表、每5分钟的状态检查等。Spring框架提供了一个简单而强大的定时任务框架——Spring Scheduler,让我们能够以声明的方式轻松实现各种定时任务需求。

本文将通过一个真实案例,带你从入门到掌握Spring Scheduler的使用。

一、Spring Scheduler简介

Spring Scheduler是Spring框架提供的定时任务调度器,它基于注解和配置的方式,让任务调度变得简单直观。主要特点包括:

  • 支持cron表达式、固定延迟、固定频率等多种调度方式
  • 与Spring容器无缝集成,可直接使用Spring管理的Bean
  • 支持异步执行和线程池配置
  • 无需额外依赖,Spring Boot中开箱即用

二、项目场景:电商订单超时处理

假设我们有一个电商系统,需要处理订单超时自动关闭的功能:订单创建后30分钟内未支付,系统自动将其标记为已关闭。

环境准备

在Spring Boot项目中,首先确保添加了基础依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring Scheduler已经在Spring Boot的web starter中包含,无需额外添加依赖。

启用定时任务

在Spring Boot主类或配置类上添加@EnableScheduling注解:

@SpringBootApplication
@EnableScheduling
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

三、实现订单超时检查任务

1. 创建订单服务

首先创建一个订单服务类,包含基本的订单处理方法:

@Service
public class OrderService {private static final Logger logger = LoggerFactory.getLogger(OrderService.class);// 模拟订单存储private Map<Long, Order> orderMap = new ConcurrentHashMap<>();private AtomicLong idGenerator = new AtomicLong(0);/*** 创建新订单*/public Order createOrder(Order order) {Long orderId = idGenerator.incrementAndGet();order.setId(orderId);order.setCreateTime(new Date());order.setStatus(OrderStatus.CREATED);orderMap.put(orderId, order);logger.info("创建订单成功,订单ID: {}", orderId);return order;}/*** 检查并处理超时订单*/public void checkAndCloseTimeoutOrders() {Date now = new Date();int timeoutMinutes = 30;for (Order order : orderMap.values()) {if (OrderStatus.CREATED.equals(order.getStatus())) {long diffInMillis = now.getTime() - order.getCreateTime().getTime();long diffInMinutes = diffInMillis / (1000 * 60);if (diffInMinutes >= timeoutMinutes) {order.setStatus(OrderStatus.CLOSED);order.setCloseTime(now);logger.info("订单超时已关闭,订单ID: {}", order.getId());}}}}/*** 获取订单状态*/public OrderStatus getOrderStatus(Long orderId) {Order order = orderMap.get(orderId);return order != null ? order.getStatus() : null;}
}/*** 订单状态枚举*/
public enum OrderStatus {CREATED,     // 已创建PAID,        // 已支付CLOSED       // 已关闭
}/*** 订单实体类*/
public class Order {private Long id;private String productName;private BigDecimal amount;private Date createTime;private Date closeTime;private OrderStatus status;// 省略getter和setter方法
}

2. 实现定时任务

现在创建定时任务类,定期检查超时订单:

@Component
public class OrderTimeoutScheduler {private static final Logger logger = LoggerFactory.getLogger(OrderTimeoutScheduler.class);@Autowiredprivate OrderService orderService;/*** 每5分钟检查一次超时订单* 使用cron表达式:每5分钟执行一次*/@Scheduled(cron = "0 */5 * * * ?")public void checkOrderTimeout() {logger.info("开始执行订单超时检查任务...");long startTime = System.currentTimeMillis();try {orderService.checkAndCloseTimeoutOrders();} catch (Exception e) {logger.error("订单超时检查任务执行失败", e);}long endTime = System.currentTimeMillis();logger.info("订单超时检查任务执行完成,耗时:{}ms", (endTime - startTime));}/*** 另一种方式:固定延迟执行* 上一次任务执行完成后,延迟5分钟再执行*/// @Scheduled(fixedDelay = 5 * 60 * 1000)// public void checkOrderTimeoutWithFixedDelay() {//     // 实现逻辑// }/*** 固定频率执行* 每5分钟执行一次,无论上一次任务是否完成*/// @Scheduled(fixedRate = 5 * 60 * 1000)// public void checkOrderTimeoutWithFixedRate() {//     // 实现逻辑// }
}

3. 测试定时任务

创建一个测试控制器来验证我们的定时任务:

@RestController
@RequestMapping("/orders")
public class OrderController {@Autowiredprivate OrderService orderService;@PostMappingpublic ResponseEntity<Order> createOrder(@RequestBody Order order) {Order createdOrder = orderService.createOrder(order);return ResponseEntity.ok(createdOrder);}@GetMapping("/{orderId}/status")public ResponseEntity<OrderStatus> getOrderStatus(@PathVariable Long orderId) {OrderStatus status = orderService.getOrderStatus(orderId);return status != null ? ResponseEntity.ok(status) : ResponseEntity.notFound().build();}
}

启动应用后,你可以:

  1. 通过POST /orders 创建订单
  2. 等待5分钟,查看日志中定时任务的执行情况
  3. 30分钟后,通过GET /orders/{id}/status 检查订单状态是否变为CLOSED

四、cron表达式详解

Spring Scheduler支持标准的cron表达式,由6个字段组成(Spring支持7个字段,包含秒):

秒 分 时 日 月 周 年(可选)

常用cron表达式示例:

  • 0 * * * * ?:每分钟执行一次
  • 0 */5 * * * ?:每5分钟执行一次
  • 0 0 * * * ?:每小时执行一次
  • 0 0 0 * * ?:每天凌晨执行
  • 0 0 12 * * ?:每天中午12点执行
  • 0 0 10,14,16 * * ?:每天10点、14点、16点执行

五、高级配置:线程池与异步执行

默认情况下,Spring Scheduler使用单线程执行所有定时任务。如果任务较多或执行时间较长,可能需要配置线程池:

@Configuration
public class SchedulerConfig {@Beanpublic TaskScheduler taskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(10); // 线程池大小scheduler.setThreadNamePrefix("scheduled-task-");scheduler.setAwaitTerminationSeconds(60);scheduler.setWaitForTasksToCompleteOnShutdown(true);return scheduler;}
}

对于需要异步执行的任务,可以结合@Async注解使用:

@Async
@Scheduled(fixedRate = 5000)
public void asyncScheduledTask() {// 这个任务会在单独的线程中异步执行
}

确保在配置类上添加@EnableAsync注解。

六、最佳实践与注意事项

  1. ​任务幂等性​​:确保定时任务可以多次执行而不会产生副作用
  2. ​异常处理​​:在任务内部妥善处理异常,避免影响其他任务执行
  3. ​分布式环境​​:在集群部署时,需要考虑使用分布式锁或只在一台实例上执行
  4. ​避免长时间执行​​:长时间运行的任务会影响其他定时任务的执行
  5. ​配置化​​:将cron表达式放在配置文件中,便于不同环境调整
# application.properties
order.timeout.cron=0 */5 * * * ?
@Scheduled(cron = "${order.timeout.cron}")
public void checkOrderTimeout() {// ...
}

七、总结

Spring Scheduler提供了简单而强大的定时任务功能,通过本文的电商订单超时处理案例,我们可以看到:

  1. 使用@EnableScheduling启用定时任务支持
  2. 通过@Scheduled注解声明定时方法,支持cron表达式、固定延迟和固定频率
  3. 定时任务方法可以是任何Spring管理的Bean的方法
  4. 可以通过配置线程池来优化任务执行性能
  5. 结合@Async可以实现异步定时任务

Spring Scheduler虽然功能强大,但在分布式环境中需要注意任务重复执行的问题。对于复杂的分布式调度需求,可以考虑使用Quartz或XXL-Job等专业调度框架。

希望本文能帮助你理解和掌握Spring Scheduler的使用,为你的项目开发提供便利。


文章转载自:

http://nRKXt8tN.hrtwt.cn
http://58EuYC7b.hrtwt.cn
http://aj3kCKuL.hrtwt.cn
http://G9QBbmsl.hrtwt.cn
http://EOCgF4Au.hrtwt.cn
http://QpDz053x.hrtwt.cn
http://ZLIWhBBM.hrtwt.cn
http://2PpgfiaJ.hrtwt.cn
http://3TLYkftO.hrtwt.cn
http://RpaYJca1.hrtwt.cn
http://ZXoD6lAW.hrtwt.cn
http://y5g8QsQb.hrtwt.cn
http://Ti4vqWxq.hrtwt.cn
http://8DebqjBq.hrtwt.cn
http://iaVILPRb.hrtwt.cn
http://J7mZ6aut.hrtwt.cn
http://KxJKaBes.hrtwt.cn
http://XDdAweII.hrtwt.cn
http://ICCCYpqI.hrtwt.cn
http://XGFJqrep.hrtwt.cn
http://yVrOvxKr.hrtwt.cn
http://I2jesFRb.hrtwt.cn
http://wpFwMO7j.hrtwt.cn
http://9uri8mPt.hrtwt.cn
http://nmFKIPi4.hrtwt.cn
http://h7XaJJ7J.hrtwt.cn
http://0QsggoRu.hrtwt.cn
http://8w1cZGWd.hrtwt.cn
http://zadBMvY3.hrtwt.cn
http://5j7vqrsu.hrtwt.cn
http://www.dtcms.com/a/375012.html

相关文章:

  • NSGA系列多目标优化算法:从理论到实践
  • 从C++开始的编程生活(7)——取地址运算符重载、类型转换、static成员和友元
  • ArcGIS学习-20 实战-县域水文分析
  • Claude Code 平替:OpenAI发布 Codex CLI ,GPT-5 国内直接使用
  • 技术速递|保护 VS Code 免受提示注入攻击
  • JAVA,IOIOIOIOIOIOIOIOIOIOIOIOIOIO
  • xv6 源码精读(一)环境搭建
  • 基于Golang + vue3 开发的 kafka 多集群管理
  • uniapp微信小程序商品列表数据分页+本地缓存+下拉刷新+图片懒加载
  • OSPF特殊区域、路由汇总及其他特性
  • 后端接口防止XSS漏洞攻击
  • Hadoop(十一)
  • 【Linux基础知识系列:第一百二十五篇】理解Linux中的init与systemd
  • iOS原生开发和Flutter开发的看法
  • 【ArkTS-装饰器】
  • XSS漏洞检测和利用
  • Vue3 生命周期函数
  • Flask/Django 生产部署:Gunicorn vs Nginx,Windows 与 Linux 实战指引
  • 从 Row 到 WaterFlow:鸿蒙应用开发ArkUI布局全家桶教程
  • 开发避坑指南(44):Mybatis-plus QueryWrapper and()拼接嵌套复杂条件的技巧
  • 消息队列(MQ)初级入门:详解RabbitMQ与Kafka
  • R语言对excel中多个sheet子表批量进行地理探测器计算
  • 开讲啦| MBSE公开课:第六集 MBSE远期目标与总结(完结)
  • 实习项目包装--HTTP 协议和 Web API
  • linux升级系统,重启出现Minimal BASH-like line editingis supported
  • ARM架构---指令集分类、内核组成,RAM与ROM的分类、工作模式、异常处理机制、立即数、s后缀、指令说明、汇编和 C 函数的相互调用
  • Qwen3微调教程:从零开始训练你的定制语言模型
  • 本地一键部署IndexTTS2,生成情绪饱满的语音,支持Windows和Mac
  • VMware虚拟机CentOS磁盘扩容完整指南(解决growpart报错 LVM扩容)
  • 【增删改查操作】