Spring博文
我真的很小心了,但还是被 SpringEvent 坑了!
网上被吹爆的Spring Event事件订阅有缺陷,一个月内我被坑了两次!
@ConfigurationProperties VS @Value,你觉得哪个更好用 - 掘金
一个注解就搞定接口统一返回、统一异常处理、加签、验签、加密、解密
SpringBoot3 优雅集成 Knife4j - 掘金
Spring Boot 3.x 中的 RestClient 使用案例-Spring专区论坛-技术-SpringForAll社区
Maven项目Parent,可以试试用这个代替 Spring Boot Parent
SpringBoot集成Logback终极指南:从控制台到云端的多维日志输出
Knife4j:实时接口文档的利器
Spring Boot的Docker Layer优化:缩小镜像体积并提升启动速度-Spring专区论坛-技术-SpringForAll社区
使用Prometheus和Grafana监控Spring Boot应用
Spring Boot 4 新特性详解:5大核心更新助力企业级开发
SpringBoot3 http接口调用新方式RestClient + @HttpExchange像使用Feign一样调用
SpringBoot + SpringCloud Gateway + Sentinel + Redis:API 网关层的接口限流、黑名单拦截与用户认证
SpringBoot + Seata + MySQL + RabbitMQ:金融系统分布式交易对账与资金清算实战
SpringBoot + MyBatis-Plus + Elasticsearch + MySQL:电商商品搜索关键词高亮与库存实时展示
SpringBoot + RabbitMQ + MySQL + XXL-Job:物流系统运单状态定时同步与异常订单重试
本文档使用 MrDoc 发布
-
+
SpringBoot + RabbitMQ + MySQL + XXL-Job:物流系统运单状态定时同步与异常订单重试
> 作者:一名 Java 开发八年老司机 > 标签:SpringBoot、RabbitMQ、MySQL、分布式任务、异常重试、物流系统 在复杂的物流系统中,“运单状态同步”是一个非常核心的功能。通常我们的系统需要定期从三方物流平台(如顺丰、京东、跨越等)拉取运单状态,然后更新本地订单状态。但现实中总是会有: - 网络请求失败 - 三方接口偶发超时 - 状态更新逻辑异常 - 甚至是 RabbitMQ 消息丢失 如果这些异常不加处理,很容易导致用户看到的订单状态延迟甚至异常,影响体验。 本文分享我在一个真实项目中,如何基于 **SpringBoot + RabbitMQ + MySQL + XXL-Job** 构建一个“**可监控、可重试、可扩展**”的运单状态定时同步系统。 ### 系统设计概述 我们将系统分为以下几个组件: ```diff +--------------------+ | XXL-Job 定时任务 | +--------+-----------+ | v +--------+-----------+ | 拉取物流运单数据 | | (调用三方API) | +--------+-----------+ | v +--------+-----------+ | 发送MQ消息 | | (RabbitMQ) | +--------+-----------+ | v +--------+-----------+ | 消费者异步处理 | | 更新订单状态 | | 写入同步日志 | +--------+-----------+ | v +--------+-----------+ | 异常重试机制 | |(失败记录表+告警) | +--------------------+ ``` ### 核心技术选型说明 | 技术组件 | 用途 | | --- | --- | | SpringBoot | 项目基础框架 | | XXL-Job | 分布式定时调度任务 | | RabbitMQ | 解耦 & 异步处理 | | MySQL | 订单与同步状态记录 | | Redis(可选) | 幂等控制、缓存 | ### 1\. XXL-Job 定时任务配置 在 XXL-Job 中配置每 5 分钟触发一次的同步任务: ```typescript ("syncLogisticStatusJob") public void syncLogisticStatusJob() { List<Order> orders = orderService.getOrdersToSync(); for (Order order : orders) { rabbitTemplate.convertAndSend("logistics.sync.exchange", "logistics.sync.routing", order.getId()); } } ``` #### 💡 实践建议 - 使用 routing key 进行精细化路由 - 批量获取待同步订单,避免一次 MQ 消息过大 - 用 Redis 记录“正在同步”的订单,避免重复同步 ### 2\. 消费者处理逻辑 ```java public void handleOrderSync(Long orderId) { try { LogisticResponse response = logisticApiClient.query(orderId); orderService.updateStatus(orderId, response.getStatus()); syncLogService.success(orderId, response.getRaw()); } catch (Exception e) { syncLogService.fail(orderId, e.getMessage()); throw new AmqpRejectAndDontRequeueException("同步失败,记录异常等待重试"); } } ``` #### 💡 实践建议 - 失败后不要重回队列,防止消息积压 - 所有异常写入日志表,便于后续人工排查或自动重试 - 使用 `AmqpRejectAndDontRequeueException` 拒绝重入队列 ### 3\. 异常日志记录与重试 失败的同步会写入一张表 `logistics_sync_log`: | 字段 | 含义 | | --- | --- | | order\_id | 订单ID | | try\_count | 当前重试次数 | | last\_error | 最近一次失败的异常信息 | | status | 成功 / 失败 / 重试中 | | next\_retry\_time | 下次重试时间 | 每隔 10 分钟,XXL-Job 启动重试任务: ```c @XxlJob("retryFailedSyncJob") public void retryFailedSyncJob() { List<SyncLog> logs = syncLogService.getRetryableLogs(); for (SyncLog log : logs) { rabbitTemplate.convertAndSend("logistics.sync.exchange", "logistics.sync.routing", log.getOrderId()); syncLogService.markAsRetrying(log.getId()); } } ``` #### 💡 实践建议 - 设置最大重试次数(如 5 次),超过则告警 - 支持手动触发重试(管理后台) - 可以引入钉钉/飞书告警通知 ### 4\. 幂等性设计 在消费者处理逻辑中加入幂等判断: ```c if (orderService.hasAlreadySynced(orderId, newStatus)) { log.info("已同步,无需重复处理: {}", orderId); return; } ``` 或者使用 Redis 分布式锁: ```ini String lockKey = "logistics:sync:" + orderId boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 5, TimeUnit.MINUTES) if (!locked) { log.info("订单 {} 正在处理中,跳过", orderId) return } ``` ### 5\. 系统监控与告警 - 同步成功率指标(Prometheus + Grafana) - 同步失败数量趋势 - 重试任务执行情况 - 异常日志告警(钉钉机器人) ### 总结 通过本文的设计与实战,我们实现了一个具有如下特性的物流状态同步系统: ✅ **高可用**:定时任务 + MQ 异步解耦 ✅ **高可靠**:失败有日志、支持重试 ✅ **易运维**:任务、日志、告警一站式管理 ✅ **可扩展**:支持多物流平台的接入 ### 源码结构参考 ```arduino com.example.logistics ├── job ├── mq ├── service ├── client ├── model ├── repository └── controller ``` ### 最后 这是我在物流系统中踩过无数坑后总结出的方案,希望对你有所启发。如果你也在做类似业务,欢迎留言交流! 别忘了点个 **赞** 或 **收藏**,让更多人看到这篇实战文章。🚀
admin
2025年10月5日 10:14
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码