当 Spring Boot 3.4.7 撞上 Spring Cloud
当 Spring Boot 3.4.7 撞上 Spring Cloud
dong4j关掉检查就行了吗
前八篇文章写了研发底座的架构全景、工程规范、Response 设计、缓存重构、配置管理、代码质量、MyBatis 组件化、网关性能调优。这些内容基本上是在同一个架构底座上逐步优化出来的。但现在我们要聊一个更底层的变动——从单体架构再切回微服务架构。
先交代一下背景。这不是一个从零开始的设计。研发底座最早是微服务架构(v2.1.0),后来因为某些项目场景需要,把它改造成了一个单体架构(代号 cirrus-1.0.0)——主要就是把原来的 Feign 远程调用改成了 JVM 内部调用,用一个聚合组件收敛依赖。然后到了 9 月,业务上又有微服务的需求了,于是我们从单体架构出发,再做一次微服务化改造,版本定为 v3.1.0。
问题是,这中间的 Spring Boot 版本变了。
单体架构改造时,根据业务方需求选择了 Spring Boot 3.4.7。这个版本号本身没问题——它是当时可用的最新稳定版。但当我们想在这个版本上加入 Spring Cloud 依赖时,启动直接炸了:
1 | *************************** |
意思很直白:Spring Boot 3.4.7 不在 Spring Cloud 官方支持的版本列表中。
为什么会这样?Spring Cloud 的发布节奏和 Spring Boot 并不完全同步。Spring Cloud 2024.0.2(代号 Moorgate)支持的 Spring Boot 版本是 3.2.x 和 3.3.x。而 3.4.7 已经超出了这个范围——对于 Spring Cloud 来说,它不认识这个版本,所以启动时内置的兼容性校验器直接拒绝启动。
解决方案就一行配置:
1 | spring: |
关了,确实能启动了。但”能启动”和”没问题”是两回事。
版本差异到底差在哪
Spring Boot 3.2.x 到 3.4.7,跨了两个小版本。按 Semantic Versioning 的约定,小版本之间应该只有功能增强和 bug 修复,不会有 breaking changes。但这是 Spring 的版本体系,不是纯 SemVer——Spring 的小版本里偶尔会有行为变更。
我们面对的风险分两类。
第一类,Spring Boot 自身的变更。3.3 到 3.4 之间有一些”优化”可能影响既有代码。比如,Spring Boot 3.3 之后,@Configuration 和 @AutoConfiguration 的界限被进一步收紧了。原来你可以用 @Configuration 写自动装配类,然后在 spring.factories 里声明——3.3 之后这不再是合法用法,Spring Boot 会在启动时报错:
1 | java.lang.IllegalStateException: The following classes could not be excluded |
因为 AjCaptchaAutoConfiguration 用的是 @Configuration 而不是 @AutoConfiguration。新版本里,只有标注了 @AutoConfiguration 的类才被视为自动装配类。这是有道理的——@Configuration 是全功能的配置类,@AutoConfiguration 是专门用于自动装配的轻量版,两者职责不同。但对于一个跨了版本的迁移项目,这种”收紧”就意味着你需要检查每一个自动装配类。
第二类,Spring Cloud 的变更。Spring Cloud 2024.0.2 相对上一个版本更新了哪些东西,我们也不完全清楚。特别是网关——原 gateway-service 是基于旧版本 Spring Cloud Gateway 写的,升级后路由配置、过滤器链、websocket 支持这些都可能受影响。
所以我当时做了个判断:先不着急写代码,而是做一个最小可启动的验证——引入 Spring Cloud 依赖,关掉兼容性检查,看能不能正常启动、正常注册到 Nacos、正常做服务发现。这就是下一节的内容。
Nacos 兼容性:服务端 2.4.3 vs 客户端 2.4.2
版本兼容性检查过了之后,接下来要验证的是 Nacos。
当时的情况是这样的:
- Nacos 服务端
sctel-postgre-nacos使用的是 Nacos Server 2.4.3 - Spring Cloud Alibaba 2023.0.3.3 内置的 Nacos Client 是 2.4.2
差了一个 bug 修复版本。理论上服务端向下兼容低版本客户端,但这个”理论”在真实跑起来之前都只是理论。
本地验证的环境很简单:先用 Docker 起一个 PostgreSQL:
1 | services: |
然后启动 Nacos。启动时要注意一件事:本地测试用单机模式就够了,不用配集群。Nacos 默认是集群模式,如果只启动一个节点,它会因为找不到其他集群节点而报错。所以本地要设置:
1 | private static boolean initEnv() { |
Nacos 启起来之后,验证三件事:
第一件,配置订阅与刷新。 在 Nacos 后台创建一个配置 test-config.yaml,内容随便写。然后本地应用通过 spring.config.import 引入这个配置,启动后确认能读到。再在 Nacos 后台修改配置内容,确认本地能实时刷新。这一步验证的是配置中心的基本能力。
第二件,服务注册。 启动一个本地微服务,配置好 spring.cloud.nacos.discovery.*,然后去 Nacos 服务列表页面确认这个服务出现了。这一步验证的是服务发现的注册功能。
第三件,服务发现。 启动两个服务 A 和 B,A 通过服务名调用 B 的接口(用 lb://service-name),确认能正常路由。这一步验证的是服务发现的调用链路。
三项都通过,版本兼容性才算基本确认。
实际测试结果是:三项全部正常。配置中心、注册中心、服务发现都工作正常。所以基于 Spring Boot 3.4.7 + Spring Cloud 2024.0.2 + Spring Cloud Alibaba 2023.0.3.3 的技术栈组合,虽然不在官方兼容列表中,但功能上可行。
但这不意味着万事大吉。我更愿意把这个验证结果理解为”最小可行性验证通过”——后面的具体组件兼容性问题,只能在遇到的时候逐个击破。
其实回头看,Spring Boot 的版本选择在技术决策里是有责任的。如果当时选型的时候用的是 3.2.x 或者等到 Spring Cloud Alibaba 2025.x 正式版发布后再动手,就不会有这个兼容性隐患。但现实就是这样——版本是业务方定的,框架组只能在这个既定事实上做改造。这也是为什么我在第一篇里提到”研发底座要有分层优化策略”——有些决策一旦做了,后面的技术债就得你自己消化。
关掉检查的真实代价
回到开头那行配置:
1 | spring: |
关了之后,Spring Cloud 就不再检查 Spring Boot 版本了。你得自己承担所有兼容性风险。
具体来说,需要在后续开发中注意:
每次升级 Spring Boot 的小版本时,重新做一次完整的兼容性测试。 3.4.7 到 3.4.8,Spring 可能修了一个 bug,但这个修复可能恰好影响了 Spring Cloud 的某个模块。
不要在同一个项目里混用不同的大版本。 父 POM 里统一管理
spring-boot-dependencies和spring-cloud-dependencies的版本号,子模块只通过dependencyManagement继承,不要自己写版本号。遇到离奇的启动报错时,第一个怀疑的应该是版本兼容性。 不要一头扎进具体的错误信息里——那种”看起来一切配置都是对的但就是不行”的问题,十有八九是版本不对。
建议的最终状态是升级到 Spring Boot 3.5.x + Spring Cloud Alibaba 2025.x。 等 Spring Cloud Alibaba 的正式版出来,版本对齐了,这行
compatibility-verifier.enabled=false就可以删掉了。
这跟第八篇里网关性能调优的教训是一样的——在出问题之前没人会关注 TIME_WAIT 的数量,就像在启动报错之前没人会关注 Spring Boot 和 Spring Cloud 的版本兼容表。
下一篇写什么
版本兼容性验证只是第一步。确认了技术可行性之后,真正的挑战才开始——你怎么让一套代码同时支持单体架构和微服务架构?Feign 接口到底该由服务提供方维护还是消费方自己写?为什么一个叫 DelegatingService 的东西成了整个迁移方案的核心?
下一篇就写这个:Feign 接口治理和 DelegatingService 模式的设计与抉择。这是一次真正需要从架构师角度做权衡的决策——两种方案,两种价值观,没有对错,只有适不适合。

















