Dante Cloud 升级 Spring Boot 4 经验分享
Java 开源圈 2025 年最引人注目的事情之一,莫过于 Spring Framework 7 和 Spring Boot 4 的发布。Dante Cloud 微服务云原生基座项目核心定位之一,就是“极尽努力与 Spring 生态的标准规范保持一致”,所以也同步开启了 适配 Spring Boot 4.X 的 Dante Cloud v4 版本的开发工作。
从 Spring Boot 4 第一个正式版本发布至今也有一个月了,Dante Cloud v4 版本也同步发布了 5 个 milestone 版本,在这个过程也积累了一些升级 Spring Boot 4 的经验,在 Spring Boot 4.0.1 发布之际,与大家分享,希望大家在后续的升级过程中尽量避坑。
介绍 Spring Framework 7 和 Spring Boot 4 新特性的文章已经非常多了,本文是从实战角度出发,结合自己的实际升级经验,对目前升级 Spring Boot 4 进行一个阶段总结。
> 我正在参加 Gitee 2025 最受欢迎的开源软件投票活动,快来给我投票吧!https://gitee.com/activity/2025opensource?ident=ICEM4T
一、 “免责声明”
说是“免责声明”其实是开玩笑,其实主要是一些注意事项:
因为每个人的项目规模以及对 Spring Boot 使用深入度的不同,在升级 Spring Boot 4 时的工作量可大可小。
例如:
- 你的项目完全是可以脱离 Spring 环境独立使用的组件,仅是定义了一个 Starter 方便 Spring Boot 环境使用,那么升级 Spring Boot 4 的工作量会非常小。
- 你的项目深度使用 Spring Boot,Spring Boot 特性用得的非常多,主要使用 Spring Boot 推荐的技术开发,甚至是多模块共享的多工程环境,那么工作量一定不小。
所以,升级 Spring Boot 4 之前,还是要结合自己的实际情况,具体分析判断。学会举一反三,切勿盲从。
二、 New Moduler Design
虽然说 Spring Framework 7 和 Spring Boot 4 新特性很多,但是代码管理以及兼容性做得非常好,对于使用者来说基本是“无感知”的。对现有代码影响微乎其微,想使用就用不想使用就不用
“New Moduler Design” 这一项对于开发者使用的影响确是最直接的,也是最明显的,也是个人认为升级 Spring Boot 4 工作量最大的一项。
1. 为什么要重新设计模块?
长久以来,Spring Boot 一直会收到诟病的点,就是启动性能方面不理想。Spring Boot 的核心模块 spring-boot-autoconfigure 是影响启动性能重要因素之一(当然还有其它因素以及其它 autoconfigure 类型的模块影响)。
随着 Spring Boot 的不断发展,集成的相关组件或技术就越来越多。每一项组件或技术的集成,都需要实现相关的自动配置以便实现各种技术的“可插拔”,而这些配置代码都放置在spring-boot-autoconfigure。
这样做的好处就是:
- 放在同一个模块好管理好维护。
- 可以更加方便的控制各种配置类和 Bean 的注入先后顺序。
这样做的坏处就是:
- Spring Boot 应用启动时,需要扫描所有的配置类和 Bean,分析其中启动顺序以及生效的条件等。Spring Boot 支持的内容越多,
spring-boot-autoconfigure就越臃肿,那么启动时需要分析的内容就越多,就会影响启动的性能 spring-boot-autoconfigure中的内容,不管你实际项目中是否用到,启动时都是需要进行分析和条件判断。
因此,Spring Boot 4 最大变化之一,就是将 spring-boot-autoconfigure 中的内容,拆分成各自独立的模块。拆分出来的模块,统一以 spring-boot-<technology> 格式进行命名。
> 例如:原本 WebClient 的默认配置代码是放置在 spring-boot-autoconfigure 模块中,被拆分出来之后,WebClient 默认的配置代码就被放置到 spring-boot-webclient 模块中
在实际开发中就不需要统一依赖 spring-boot-autoconfigure,根据需要用到那种技术就手动依赖相关的 spring-boot-<technology> 模块或者对应的 Starter。
这样可以极大地减少启动时配置类的扫描和分析,以达到提升性能的目的
2. 拆分后如何控制配置注入顺序?
这个问题其实是 spring-boot-autoconfigure代码拆分后的最大问题,为了解决这个问题 Spring Boot 在 @AutoConfiguration 中新增两个属性:aftername和 beforename。通过这两个属性,你可以直接以“字符串”形式配置其它模块某个配置类的完整类路径。
这样就不用再通过依赖模块,配置具体 Class 的方式控制配置顺序,而且解决了跨模块控制配置类顺序的问题
3. 为什么升级工作量大?
> 工作量大不大,请结合“免责声明”章节内容,还是要结合项目实际情况而定,切勿无脑抬杠。
Spring Boot 4 “New Moduler Design”带来了性能的提升,同时也给升级带来了最大阻碍。
原本所有代码都是放置在 spring-boot-autoconfigure中,工程中默认就依赖了。不管是你自己的配置类中自动注入相关的配置,还是代码中用到了其中的代码都非常方便。
Spring Boot 4 将spring-boot-autoconfigure中的代码拆分为不同模块之后,其中还会涉及到类路径的变化。
如果你的代码用到了很多spring-boot-autoconfigure中的代码,那么在升级 Spring Boot 4 时,不仅要找打原有代码所在的新模块,还要去找对应的类在新模块中所在的包。因为没有统一的可以索引的地方,只能自己慢慢地找。
> 作者是直接将 Sping Boot 的源码下载下来,找不到代码时就在 Spring Boot 源码中全文搜索。
4. 带来的启示
原本 Spring Boot 2.X 升级 3.X 时,除了一些特性的变化外,整体的代码结构和包路径还是基本保持一致,这种情况下还可以考虑一下兼容问题。
因为,Spring Boot 4 中会出现很多类的包路径变化的情况,这样就很难考虑兼容的问题。(类路径都变了,考虑兼容还有什么意义)
所以,如果你的项目原本需要考虑兼容性的,升级 Spring Boot 4 时就别考虑兼容问题了,都是无用功。
三、 周边生态的适配
升级 Spring Boot 4 另一项重要工作,就是你所使用到的周边第三方组件的适配。之所以说这项工作重要,原因其实在前面的内容中已经说到了,就是:Spring Boot 4 中很多类的包路径变了,这是没有什么好办法进行兼容处理的,只有等者周边生态软件的适配。
> 如果不适配会直接影响代码运行的
以 Dante Cloud 项目为例,需要等待适配的周边,以及相关的进度如下:
Spring Cloud Alibaba:已经有 Committer 提交了适配代码,因为项目在考虑彻底删除对 Bootstrap 模式的支持,所以还没有发测试或者正式版本Spring Cloud Tencent:项目团队人员少,在等着社区 Committer 贡献适配代码Spring Boot Admin:正在适配中Resilience4j:还没有看到相关计划Jasypt Spring Boot Starter:时隔几年才刚发布适配 Spring Boot 3.5 版本,适配 Spring Boot 4 还得等
四、 Jackson3
Spring Boot 4 中另一项比较有影响的变化就是开始使用 Jackson 3。
Jackson 3 主要的变化有:
com.fasterxml.jackson变为tools.jackson。所以,如果你深度使用 Jackson 还想用 Jackson3,那么会大量修改包路径的工作- new ObjectMapper 已经不推荐使用。需要使用以下方式创建:
this.objectMapper = JsonMapper.builder()
.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)
.enable(JsonReadFeature.ALLOW_SINGLE_QUOTES)
.enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS)
.build();
- 注解相关配置方式变化
JsonMapper.builder()
.changeDefaultPropertyInclusion(incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL))
.build();
- 部分原有需要手动关闭的配置,目前 Jackson3 已经修改默认关闭
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
- Jackson3 所有方法统一抛出
JacksonException
注意事项
- jackson3 中,还是使用的 jackson 2.x annotation 模块,所以如果使用了 jackson 注解,注解的坐标还是
com.fasterxml.jackson,所以在修改 jackson 3 包名时,如果想用 IDE 进行全局包路径替换一定要谨慎,以防改错。 - Spring Boot 4 还保留了 Jackson 2 的支持。Jackson 2 的代码均放置在
**.Jackson2.**包下面,而 Jackson 3 的代码均放置在**.Jackson.**包下面
五、 commons-lang3
Spring Boot 4 基础依赖的 commons lang3 已经升级至 3.19.0。
自 commons lang3 3.18.0 版本起,String 相关操作工具类有了较大变化,原有 StringUtils.XX,拆分为 Strings.CI.XX 和Strings.CS.XX
因此,还会涉及大量包路径的修改
> 升级至 3.19.0,原有方法 StringUtils.XX 仍然可用,不过又有大量过时告警。
六、 JSpecify
Spring Boot 4 中,全面引入 JSpecify 相关注解进行空值标注。
所以建议将原有 Spring 提供的 Nullable 以及 IDEA 提供的 NotNull 注解全部替换为 JSpecify。
> 注意:如果你实现或者扩展了 Spring 或者相关组件的一些方法,建议检查一下是否已经变换为 JSpecify 注解。如果变换了建议将自己的实现方法同步修改一下
七、 API 版本
Spring Boot 4 中最吸引人的另一个功能,莫过于对于 API 版本的支持。Dante Cloud 也同步增加了对 API 版本动态鉴权的支持。
Spring Boot 4 API 版本,支持 Query 参数版本、路径版本、以及请求 Header 版本三种,获取版本方式。需要结合自己的实际进行修改。
> 如果你想支持 API 版本,同时支持 API 接口的动态鉴权,那么会有一定的工作量
八、 Undertow 移除
Undertow 作为一款高性能的 Web 容器,深受用户喜爱。但是因为对 Servlet 6.1 支持度较差,不符合 Spring Boot 的发展方向,所以在 Spring Boot 4 中已经将 Undertow 相关的支持移除。
因为 Dante Cloud 一直以来都在使用 Undertow 作为 Web 容器,所以不得不在新版本中进行更换。最早是更为换 Tomcat,但是 Tomcat 过于厚重、性能优化配置繁琐、启动速度明显慢,所以最终还是更换为更加轻量的 Jetty。
总结
整体而言,升级 Spring Framework 7 和 Spring Boot 4 机制方面的变化,对于用户来说是“无感的”。Dante Cloud 升级 Spring Boot 4 的工作,其实大量的工作都是在修改“包路径”。
升级 Spring Boot 3.X 时,大部分人还抱着“怀疑”、“观望”的态度。但是到了 Spring Boot 4.X,很多开源社区在正式版未发布之前就已经开始着手适配工作。可见其对于用户吸引力有多打。
Spring Boot 4 机制以及对性能的提升,特别是对 JDK 25 的支持,非常值得一试。 目前升级 Spring Boot 4 最大的难点就在于周边生态的适配度。
如果本项目对你有所帮助,欢迎 Star 一波来支持我们!
Github:https://github.com/dromara/dante-cloud
Gitcode:https://gitcode.com/dromara/dante-cloud