Spring Boot 3发布至今已经有相当长的时间,但仍有很多团队停留在Spring Boot 2.x版本上观望。原因不外乎两点:一是升级牵扯到JDK版本和依赖包名的变更,改造成本不小;二是不清楚升级后到底能获得什么好处,值不值得投入。这篇文章就把两个版本之间的核心差异、配置变化、优化技巧以及升级过程中的常见坑一次性讲清楚,帮你做决策、做迁移。

一、底层依赖的演进:JDK 17与Jakarta EE是分水岭
Spring Boot 3最根本的变化发生在底层。它基于Spring Framework 6构建,而Spring Framework 6做了一个硬性要求:最低JDK版本提升到17。这不是官方故意抬高门槛,而是因为Spring Framework 6全面拥抱了JDK 17的语言特性,包括record、密封类、文本块以及虚拟线程的适配准备。如果你的项目还跑在JDK 8或者JDK 11上,那么升级Spring Boot 3之前必须先把JDK升上去,这一步往往比升级Spring Boot本身工作量更大,涉及编码规范、依赖库兼容性等多个方面。
另一个重大变更是命名空间从javax.*迁移到jakarta.*。这源于Jakarta EE 9的规范调整,所有Servlet、JPA、Validation相关的包名全部改了。举个例子,以前你写的import javax.persistence.Entity在Spring Boot 3中必须改成import jakarta.persistence.Entity。这个变更会波及所有使用了JPA、Servlet API、Bean Validation的项目,几乎是全量的import修改。好消息是IDE都提供了批量替换能力,配合OpenRewrite等自动化迁移工具可以大幅降低人工成本。
除了以上两点,Spring Boot 3还把基线依赖整体刷新了一轮:Servlet容器默认支持Tomcat 10.1、Jetty 11,Hibernate升级到6.x,这些上游组件的升级同样会带来行为差异,比如Hibernate 6对SQL的生成策略、方言处理都有调整,某些在5.x下正常执行的JPQL可能在6.x下报错,需要重点回归测试。
二、核心新特性:原生镜像、可观测性与声明式HTTP客户端
Spring Boot 3最重要的新能力是AOT(Ahead-Of-Time)处理与GraalVM原生镜像支持。通过native-maven-plugin或native Gradle插件,可以把应用编译成原生可执行文件,启动时间从数秒压缩到百毫秒级别,内存占用也显著下降。这对Serverless场景和弹性扩缩容非常友好。不过要清楚,原生镜像需要闭环的反射配置,使用了大量动态反射、动态代理的框架需要额外的hints配置,不是所有项目都能无痛享受这个红利。
第二个值得关注的增强是可观测性。Spring Boot 3引入了Micrometer Observation API,把原来分散的指标、日志、链路追踪统一到一个抽象层。你只需引入micrometer-tracing相关的桥接包(比如Bridge Brave),就能自动为HTTP请求、定时任务等添加链路追踪能力,代码几乎不用改动:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<scope>runtime</scope>
</dependency>第三个实用改进是新增的声明式HTTP客户端@HttpExchange。它类似于OpenFeign的体验,但属于Spring Web原生支持,只需定义接口并标注@GetExchange、@PostExchange等注解,再配合一个WebClient实例即可完成远程调用,省去了手写大量样板代码。此外,Spring Boot 3还支持可观察的RestTemplate、更友好的@FallbackBean处理、Problem Details标准错误响应(RFC 7807)等特性,这些都能在具体业务场景中提升开发效率。
三、配置方法的变化与升级迁移步骤
配置层面两个版本的差异主要体现在属性废弃与默认值调整上。Spring Boot 3清理了大批2.x中标记废弃的属性,例如spring.mvc.throw-exception-if-no-handler-found等被移除或替换。同时部分默认行为也变了:Trailering相关配置、server.max-http-header-size改名为server.max-http-request-header-size,MySQL驱动的坐标从mysql:mysql-connector-java改为com.mysql:mysql-connector-j。升级后如果配置项被静默忽略,应用行为可能与预期不符,建议在启动时开启属性迁移检查。
推荐的迁移路径是分四步走。第一步,先把Spring Boot 2升级到2.7.x,这是官方指定的过渡版本,2.7提供了大量废弃提示和迁移指引;第二步,将JDK升级到17,验证所有依赖在JDK 17下可正常运行,重点关注老版本的ASM、CGLIB等字节码库;第三步,执行包名替换,把javax批量替换为jakarta(注意只替换EE相关的包,不要误改javax.swing这类JDK自带包);第四步,把parent版本改为3.x并处理编译错误。整个过程中强烈建议配合OpenRewrite自动化脚本:
# 使用OpenRewrite自动执行Spring Boot 3迁移 mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \ -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:RELEASE \ -Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_1
除了迁移,配置优化方面也有几个技巧可以复用。第一,善用spring.config.import取代原来的多文档配置文件拆分,配置拆分更清晰;第二,利用Spring Boot 3.0后内置的配置属性文档生成能力,在编译期自动生成spring-configuration-metadata.json,让IDE对自定义配置项也能智能提示;第三,生产环境建议开启-XX:+UseZGC或JDK 21虚拟线程(需3.2以上版本,配置spring.threads.virtual.enabled=true),应对高并发IO密集场景效果明显。
四、常见问题与注意事项
升级过程中最常见的问题是启动直接报错ClassNotFoundException: javax.servlet.http.HttpServletRequest,这几乎百分百是某个第三方依赖还在使用旧的javax命名空间。解决办法是排查该依赖是否有jakarta适配版本,例如旧版Swagger需要换成springdoc-openapi v2,Axis、老版本CXF等没有适配的组件则需要寻找替代方案。判断依赖是否受影响,可以用mvn dependency:tree查看传递依赖,再结合jdeps工具扫描jar包内的javax引用。
第二个高频问题是Hibernate 6带来的SQL行为差异。部分复杂JPQL、native query分页、以及hibernate.dialect显式配置在6.x下可能失效或报错。Hibernate 6已经能自动探测数据库版本,多数场景下直接删掉方言配置即可;如果必须指定,注意方言类名从org.hibernate.dialect.MySQL8Dialect调整为org.hibernate.dialect.MySQLDialect这种统一命名。另外,字符集处理也有变化,Hibernate 6默认以Unicode处理,某些依赖数据库默认排序规则的旧表可能出现乱码或查询异常。
最后提醒几个容易忽视的细节。一是Spring Boot 3不再提供对旧版Actuator端点ID的驼峰兼容,自定义端点ID必须是kebab-case;二是trailing slash匹配默认关闭,/api/user/不再等价于/api/user,前端路由需要同步调整;三是如果你在用Spring Cloud,版本必须配套升级到2022.x以上,Spring Cloud 2021与Spring Boot 3不兼容。建议升级前先跑通全量测试用例,灰度发布验证关键链路,再逐步放量。总体来看,Spring Boot 3的升级短期有成本,但换来的长期维护性、性能空间和新特性支持是值得的,新项目应直接从3.x起步。
Spring Boot 3Spring Boot 2配置迁移修改时间:2026-09-06 13:44:52