Boot4升后Spring Retry依赖怎么管

升 Boot4 后,Boot 不再托管 spring-retry 版本。本稿讲怎么认、怎么显式钉版本或迁 Framework 原生重试、怎么验,不写 AMQP/Kafka Customizer 细节。

同系列:AMQP retry 属性怎么改、Kafka retry 属性怎么改、Session Mongo 怎么迁、CLASSIC 加载器怎么删------一句对照,不写进本稿交付。

Boot4 升后为什么 spring-retry 突然要自己写版本?

Spring Boot 4.0 Migration Guide 里 Dependency Management for Spring Retry 写得很直:

Dependency management for Spring Retry has been removed . If you still depend on Spring Retry, an explicit version is now required. Please consider moving your use of Spring Retry to Spring Framework.

也就是说:不是「禁止再用 spring-retry」 ,而是 Boot 不再在 BOM / 依赖管理里替你钉版本------portfolio 能力往 Framework 核心重试收之后,Boot 把这块托管拿掉了。以前靠 Boot BOM「偷」到 org.springframework.retry:spring-retry 版本的工程,升 4.0 后常见现象是:

现象 大致原因
Maven/Gradle 解析失败:spring-retry 无版本 Guide:explicit version required
依赖树里版本漂移 / 被其它 BOM 顶掉 Boot 不再统一托管
以为跟 AMQP RabbitRetryTemplateCustomizer 改名是同一坑 不是(见后文分列)
以为跟 Kafka retry random→jitter 是同一坑 不是(见后文分列)

本稿只盯 Boot 不再管 spring-retry 版本怎么认、怎么钉版本或迁 Framework;不把消息侧 Customizer / 属性文再写一遍。其它 Boot4 主题见文首内链。

认坑时先问一句:失败发生在「解析依赖」还是「改消息重试钩子」? 前者走本稿;后者去看 AMQP/Kafka 那两篇。混判最常见的代价是:Customizer 改完了,CI 仍报 spring-retry 缺版本。

先过一张迁移总览图:

图:旧 Boot BOM 托管 spring-retry → Boot4 依赖管理 Removed → 短期显式 version,或中期迁 Framework 原生重试 → 依赖树与编译冒烟。

和 AMQP / Kafka 的 retry 文是同一篇吗?

不是------同「retry」字样,主线不同,必须分列。

维度 本稿(Spring Retry 依赖管理) AMQP(169730707) Kafka(169145369)
Guide 落点 Dependency Management for Spring Retry removed Spring AMQP Retry Features · Customizer 改名 Kafka retry 退避键等属性迁
你改什么 pom/gradle 版本托管;或迁 Framework 注解/API RabbitRetryTemplateCustomizer → Template/Listener Customizer 消息消费侧 retry 属性
还能不能继续用旧库 短期可以,但须 显式 version 旧 Customizer 接口要迁 属性键要迁
能否一套 MR「一把梭」 不建议 不建议 不建议

一句话:本稿管的是 「谁给你 spring-retry 的版本号」 ;那两篇管的是 消息中间件重试钩子/属性怎么改。升版清单里若写「凡带 retry 字样照 AMQP 文抄」,很容易漏掉 BOM 层解析失败。

旧写法长什么样(Boot3,勿再沿用)

Boot 3.x 常见心智是:业务或 starter 间接引入 spring-retry,自己不写 version ,指望 spring-boot-dependencies 管住。下面是失效示意------升 Boot4 后请按路径改,不要当可用模板。

旧依赖假设(示意 · 失效)

xml 复制代码
<!-- Boot 3.x 常见:不写 version,靠 Boot BOM 托管 ------ 升 Boot4 后会解析失败或漂移 -->
<dependency>
  <groupId>org.springframework.retry</groupId>
  <artifactId>spring-retry</artifactId>
  <!-- 无 <version>:Boot4 起不再由 Boot 依赖管理提供 -->
</dependency>
kotlin 复制代码
// Gradle 旧假设示意(失效)
// implementation("org.springframework.retry:spring-retry")  // 无 version

父 POM、BOM overlay、多模块里「以为 Boot 会一直带版本」的传递依赖,同样要扫------Guide 口径是 removed,不是「悄悄换了另一个坐标」。

短期怎么改:显式声明 version

若业务短期仍要 spring-retry(注解、RetryTemplate 旧 API、与存量 @Recover 等耦合深),Guide 允许继续用,但 必须自己钉版本:

xml 复制代码
<!-- Boot4:仍依赖 spring-retry 时须显式 version -->
<!-- 版本号以你们与 Boot4 / Framework 的兼容矩阵为准,勿照抄第三方博文「最新号」 -->
<dependency>
  <groupId>org.springframework.retry</groupId>
  <artifactId>spring-retry</artifactId>
  <version>${spring-retry.version}</version>
</dependency>
kotlin 复制代码
// Gradle:显式 version(占位,勿编造具体号)
implementation("org.springframework.retry:spring-retry:${springRetryVersion}")

实务建议:

  1. 在父 POM / gradle.properties 集中定义 ${spring-retry.version},避免子模块各写各的。
  2. 升版 MR 里把「无 version 的 spring-retry」当成门禁项:dependency:tree / dependencies 搜一遍。
  3. 不要 指望再加一个「Boot Retry starter」就能恢复 BOM 托管------Guide 写的是依赖管理 removed,不是改 starter 名字。
  4. 若公司有内部 BOM(platform / bill-of-materials),确认里面是否仍声明 spring-retry;内部 BOM 有托管 ≠ Boot 官方又管回来了,两边版本策略要写进升版说明,避免「本地绿、流水线红」。
  5. 多模块工程优先在 dependencyManagement 钉一处,业务模块只写坐标不写号;Gradle 则用 platform / 版本目录对齐同一来源。

短期钉版本能让构建先绿;中期仍建议按 Guide 评估迁 Framework。钉版本不等于「技术债清零」------只是把「谁负责选版本」从 Boot BOM 交回你们自己的兼容矩阵。

中期怎么改:迁 Spring Framework 原生重试

官方鼓励把 Spring Retry 的用法迁到 Spring Framework Resilience。证据核对过的落点:

项 值
启用 @EnableResilientMethods(org.springframework.resilience.annotation,Since 7.0)
声明式 同包 @Retryable;属性注意 maxRetries (不是旧 spring-retry 的 maxAttempts)
次数含义 total attempts = 1 + maxRetries(首次执行 + 重试次数)
编程式 org.springframework.core.retry.RetryTemplate

声明式短例(import 齐全)

java 复制代码
package com.example.retry;

import org.springframework.context.annotation.Configuration;
import org.springframework.resilience.annotation.EnableResilientMethods;
import org.springframework.resilience.annotation.Retryable;
import org.springframework.stereotype.Service;

/**
 * Boot4 / Framework 7:原生重试示意。
 * 注意:@Retryable 用 maxRetries,不是旧 spring-retry 的 maxAttempts。
 */
@Configuration
@EnableResilientMethods
class ResilienceConfig {
}

@Service
class OrderRemoteClient {

    @Retryable(maxRetries = 3)
    public String fetchOrder(String id) {
        // 调用下游;失败时按 maxRetries 重试
        // total attempts = 1 + 3
        return remoteCall(id);
    }

    private String remoteCall(String id) {
        // ...
        return id;
    }
}

要点:

  • 配置类上开 @EnableResilientMethods,业务方法上挂 @Retryable(maxRetries = ...)。
  • 从旧 @Retryable(maxAttempts = n) 迁过来时,不要原样抄属性名 ------Framework 侧是 maxRetries;次数语义按「1 + maxRetries」核对,避免「少重试一次 / 多重试一次」的静默偏差。
  • 编程式场景用 org.springframework.core.retry.RetryTemplate(包名已是 Framework 核心,不是 org.springframework.retry.support)。

关于旧 @Recover:不要按一对一搬家假设

旧 spring-retry 里常见 @Recover 做最终失败回退。证据结论:不要按「注解一对一搬家」来假设 。迁 Framework 时,失败回退请按 resilience 文档 与你们现有错误处理(显式 catch、补偿任务、消息 DLQ 等)单独设计,不要假设注解一对一搬家。

怎么快速核:依赖树里还有没有「靠 BOM 偷来的」spring-retry?

验收图:

图:对照 Guide → 搜无 version 残留 → 选显式版本或 Framework → 依赖树 + 编译/重试冒烟。

搜残留(示意命令)

bash 复制代码
# 仓库全文
rg -n "spring-retry|org\\.springframework\\.retry" --glob '!**/target/**' --glob '!**/build/**'

# Maven 依赖树(看是否仍无托管版本或被其它 BOM 顶掉)
mvn -q dependency:tree -Dincludes=org.springframework.retry:spring-retry

# Gradle
./gradlew dependencies --configuration runtimeClasspath | rg spring-retry

冒烟 checklist

  1. 对照 Guide:能指到「Dependency Management for Spring Retry」段,确认 removed + explicit version + consider Framework。
  2. 构建 :无 version 的 spring-retry 声明已消失;显式 version 或已删依赖并改 Framework。
  3. 编译 :相关模块 compile / testCompile 通过。
  4. 行为 :选一条原先靠重试兜住的路径,确认重试次数与失败回退符合预期(迁 Framework 时尤其核对 maxRetries 语义)。
  5. 边界 :本 MR 不 改 AMQP Customizer、不 改 Kafka retry 属性、不动 Session Mongo / CLASSIC。

补充一个最小「次数语义」手算:旧 spring-retry 里很多人习惯 maxAttempts = 3 表示一共试 3 次;Framework @Retryable(maxRetries = 3) 表示 额外重试 3 次 ,加上首次共 4 次。迁移表或单元测试里把「期望调用次数」写清楚,避免评审口头说「还是 3」实际却偏了一次。编程式 RetryTemplate 同样按 Framework 文档配置策略,不要把旧 SimpleRetryPolicy#setMaxAttempts 的数字无脑贴过去。

边界与勿踩

  • 不要 把本稿写成 AMQP RabbitRetryTemplateCustomizer 迁改文------那是 169730707。
  • 不要 写成 Kafka retry 属性迁改文------那是 169145369。
  • 不要 抢昨日 Session Mongo 直持移除(169807868)、CLASSIC 加载器(169615117)。
  • 不要 宣称旧 @Recover 可在 Framework 侧原样照搬;回退路径需单独设计。
  • 不要编造具体「官方推荐最新 spring-retry 版本号」------用属性占位,以兼容矩阵为准。
  • 不要 把 @Retryable 的 maxAttempts 原样抄到 Framework 注解上------应用 maxRetries。
  • 不要把 WebClient 超时配置扯进本稿主线(另文禁写项,此处不展开)。
  • 真相源:Migration Guide、Framework Resilience。

和「半吊子升级」怎么划清

实务里最常见的失败不是「忘了写一个数字」,而是 只做了一半:

  • 业务模块显式钉了 version,测试模块 / 插件模块仍靠「幻想中的 Boot BOM」;
  • 或者:依赖树绿了,但代码仍混用旧 org.springframework.retry.annotation.Retryable 与新 org.springframework.resilience.annotation.Retryable,属性名抄错;
  • 或者:看见「retry」就去改 AMQP/Kafka Customizer,BOM 层解析失败原样留着;
  • 或者:删了 spring-retry 依赖,却没开 @EnableResilientMethods,重试静默消失;
  • 或者:把 maxAttempts=3 改成 maxRetries=3 却没核对「1 + maxRetries」语义,线上重试次数偏了。

还有两类更容易被评审漏掉:

  • 只改了文档、没改构建 :README / 内部 Wiki 写了「Boot4 要显式版本」,但父 POM 的 dependencyManagement 里仍没有 spring-retry,子模块也没写 <version>------CI 一换干净缓存就红。
  • 只迁了注解、没迁编程式入口 :方法上换成了 Framework @Retryable,角落里还有 org.springframework.retry.support.RetryTemplate 手工 new;两套重试栈并存,排障时日志对不上次数。

门禁上建议把「搜无 version 的 spring-retry」和「确认迁路径已落地(显式版本 或 Framework)」写成同级检查;再加一条「旧包名 org.springframework.retry 与新包名 org.springframework.resilience / org.springframework.core.retry 是否 intentional 共存」。门禁不过就别合主分支。

FAQ

Boot4 升后为什么 spring-retry 突然要自己写版本?

Migration Guide:Dependency management for Spring Retry has been removed ;仍依赖则 explicit version is now required。

和 AMQP / Kafka 的 retry 属性迁移是同一篇文章吗?

不是。本稿是 BOM/依赖管理;那两篇是消息侧 Customizer / 属性。分列,见 169730707、169145369。

还能继续用 spring-retry 吗?还是必须立刻删掉?

还能用。Guide 要求显式版本,并 鼓励 迁 Framework;不是「升 Boot4 当天必须删库」。

迁到 Spring Framework 原生重试要开什么开关?

@EnableResilientMethods;方法上 @Retryable(maxRetries = ...)。文档见 Framework resilience。编程式用 org.springframework.core.retry.RetryTemplate。

怎么快速核依赖树里还有没有靠 Boot BOM 偷来的 spring-retry?

dependency:tree / dependencies 搜 org.springframework.retry:spring-retry;再全文搜无 version 的坐标声明。

旧的 @Recover 怎么办?

不要按注解一对一搬家来假设。按 Framework 文档与现有失败处理单独设计回退路径。

小结 checklist

  • 认清 Removed:Boot 不再托管 spring-retry 依赖管理
  • 短期:pom/gradle 显式 version(以兼容矩阵为准,勿瞎编最新号)
  • 中期:迁 Framework --- @EnableResilientMethods + @Retryable(maxRetries=...);或 RetryTemplate
  • 核对次数语义:total attempts = 1 + maxRetries(非旧 maxAttempts 原样照搬)
  • 勿假设旧 @Recover 可原样照搬到 Framework
  • 与 AMQP(169730707)、Kafka(169145369)分列;勿抢 Session Mongo(169807868)、CLASSIC(169615117)
  • 验收:对照 Guide → 清无 version 残留 → 依赖树 + 编译/重试冒烟
  • 勿把 WebClient 超时扯进主线;勿编造证据外类名/版本号
  • 真相源:Migration Guide、Framework resilience 文档

按「对照 Guide → 显式钉版本或迁 Framework → 依赖树干净 → 编译/重试冒烟」改完,这类踩坑通常一次就能闭环。别在「是不是某个 starter 名字变了」上反复猜。其它 Boot4 能力见前述内链,本文不展开。

相关推荐
ZealSinger2 天前
Boot4升后AMQP retry属性怎么改
amqp·boot4·升级踩坑·rabbitretry
ZealSinger3 天前
Go1.27升后trace http怎么监听
go1.27·升级踩坑·go-tool-trace·http监听
ZealSinger4 天前
Go1.27升后GODEBUG旧值怎么处理
go1.27·升级踩坑·godebug·asynctimerchan
行者-全栈开发5 天前
【码动四季·秋】把 Spring Boot 的 Tomcat 换成 Undertow:一次容器替换的三处暗坑
spring boot·tomcat·容器化·依赖管理·undertow
ZealSinger8 天前
Boot4升后Kafka retry属性怎么改
kafka·retry·boot4·升级踩坑
ZealSinger9 天前
Boot4升后session_redis属性怎么改名
redis·springsession·boot4·升级踩坑
AI 编程助手GPT13 天前
GPT 脚本别只发一个文件:用 uv 把依赖和锁一起交付
人工智能·python·gpt·uv·依赖管理
ZealSinger14 天前
Boot4升后HttpServiceClient怎么换
boot4·httpservice·importhttp·升级踩坑
ZealSinger18 天前
Boot4升后WebClient starter怎么换
starter·webclient·restclient·boot4