Java 21和Spring Boot 3升级笔记(二)Jakarta迁移要点

发表于 2024-09-23 21:46 1004 字 6 min read

Spring AI学习笔记(四)工具调用和MCPSpring AI学习笔记(三)RAG从文档入库到回答Spring AI学习笔记(二)ChatClient从怎么调到怎么封装Spring AI学习笔记(一)它到底解决什么问题java新版本-java25学习笔记(四)用JFR和GC日志做一次体检java新版本-java25学习笔记(三)虚拟线程要和资源边界一起看java新版本-java25学习笔记(二)运行时基线先统一java新版本-java25学习笔记(一)LTS版本对比和学习路线主流AI Agent能力对比与工程选型我用Kiro做了个自己的工具站盘一盘虚拟线程我用Trae做了个AstrBot的AI角色扮演插件Python初学笔记(六)常用标准库先学这几个Python初学笔记(五)读写文件和处理异常Python初学笔记(四)函数让代码开始有结构Python初学笔记(三)条件、循环和推导式Python初学笔记(二)变量和基础类型比想象中重要Python初学笔记(一)先把环境和运行方式弄明白主流AI大模型能力对比Java 21和Spring Boot 3升级笔记(五)日志指标与可观测性Java 21和Spring Boot 3升级笔记(四)数据访问层适配Java 21和Spring Boot 3升级笔记(三)虚拟线程使用边界Java 21和Spring Boot 3升级笔记(二)Jakarta迁移要点Java 21和Spring Boot 3升级笔记(一)工程基线整理魔法值怎么能忍!JPA的Specification大改造!处理生僻字乱码:JPA框架对于Oracle的NVarchar2,NChar,NClob类型支持Redis Stream能不能当轻量消息队列用RocketMQ 5学习笔记:普通消息之外要看什么事件流不是换个消息队列这么简单Kubernetes学习笔记04:发布、排障和观测Kubernetes学习笔记03:配置、密钥和存储Kubernetes学习笔记02:Deployment、Service和IngressKubernetes学习笔记01:Pod和控制器mysql索引原理02--存储引擎索引的实现mysql索引原理01--索引的数据结构
  从 Spring Boot 2 升到 Spring Boot 3,一个很明显的变化就是变成了。   刚开始看,这好像只是包名改了。把改成,把改成,编译通过就行。   但实际迁移时我觉得没这么简单。包名变化背后影响的是整套 Jakarta EE 生态,Servlet、Validation、Persistence、Annotation...

前言

  从 Spring Boot 2 升到 Spring Boot 3,一个很明显的变化就是javax.*变成了jakarta.*

  刚开始看,这好像只是包名改了。把javax.servlet改成jakarta.servlet,把javax.validation改成jakarta.validation,编译通过就行。

  但实际迁移时我觉得没这么简单。包名变化背后影响的是整套 Jakarta EE 生态,Servlet、Validation、Persistence、Annotation 这些都会被牵连。项目越老,历史依赖越多,越容易在这里踩坑。

先全局搜索 javax

  迁移第一步很朴素:全局搜索javax.

常见的地方有:

1.Controller 里的 Servlet API。 2.DTO 或参数对象上的校验注解。 3.JPA 实体上的持久化注解。 4.过滤器和拦截器。 5.自定义注解和扩展类。

比如原来可能是:

import javax.validation.constraints.NotBlank;
import javax.persistence.Entity;
import javax.servlet.http.HttpServletRequest;

迁移后要变成:

import jakarta.validation.constraints.NotBlank;
import jakarta.persistence.Entity;
import jakarta.servlet.http.HttpServletRequest;

这一步可以靠 IDE 批量处理,但不要只靠自动替换。因为有些第三方依赖还停留在javax时代,强行改业务代码以后,依赖本身可能仍然不兼容。

第三方依赖更麻烦

  真正麻烦的通常不是自己项目里的 import,而是第三方库。

比如一个老的 starter、老的权限框架、老的 Swagger 组件,如果内部还依赖javax.servlet,在 Spring Boot 3 下就可能直接启动失败。

这类问题一般有三种处理方式:

1.升级到支持 Spring Boot 3 的版本。 2.换成新的替代库。 3.如果是内部组件,就跟着一起迁移。

最不建议的是在项目里硬凑各种兼容包。短期可能能启动,长期会让依赖树变得很乱。

所以升级前可以先看依赖树:

mvn dependency:tree

重点看有没有老的javax.*相关依赖,以及有没有版本被手工锁死。

Validation 要重新测

  校验注解从javax.validation变成jakarta.validation以后,很多代码改完能编译,但不代表运行行为完全没问题。

比如 Controller 参数校验、嵌套对象校验、分组校验、自定义 Validator,都要跑一遍。

常见写法:

public class CreateOrderRequest {

    @NotBlank(message = "订单号不能为空")
    private String orderNo;

    @NotNull(message = "金额不能为空")
    private BigDecimal amount;
}

如果自定义校验器还引用旧包,就会报错。比如:

public class OrderNoValidator
        implements ConstraintValidator<OrderNo, String> {
}

这里的ConstraintValidator也要确认来自jakarta.validation

JPA 实体要小心

  如果项目使用 Spring Data JPA,实体注解也要迁移到jakarta.persistence

比如:

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

这部分看起来简单,但要注意 Hibernate 版本也跟着变了。Spring Boot 3 默认使用 Hibernate 6,SQL 生成、类型映射、方言配置都有可能和老版本不同。

所以不要只看实体能不能启动。最好挑几条核心查询、分页查询、更新语句、复杂 Specification 都跑一下。

尤其是 Oracle、PostgreSQL、MySQL 混用的项目,更要看方言和字段类型映射。数据库层的问题有时不会在启动时暴露,而是在某个接口第一次执行时才出现。

Servlet 过滤器也要检查

  很多项目会有自定义 Filter,比如日志过滤、鉴权过滤、跨域处理。

这类代码一般会用到:

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;

如果 Filter 注册方式比较老,也可以顺手整理一下。比如统一用FilterRegistrationBean,明确顺序和 URL 范围。迁移时把这些边界写清楚,后面排查请求链路会轻松很多。

小结

  Jakarta 迁移表面上是包名变化,实际上是在检查整个项目的 Web、校验、持久化和第三方组件是否跟上 Spring Boot 3 生态。

  我的建议是:先全局处理业务代码,再用依赖树排查第三方库,最后用核心接口做回归。不要只满足于编译通过,尤其是 Validation、JPA 和 Filter 这些运行期行为,一定要实际测。

喜欢的话,留下你的评论吧~

© 2019 - 2026 VincentHo @VincentHo
Powered by theme astro-koharu · Inspired by Shoka