前言
从 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 这些运行期行为,一定要实际测。
喜欢的话,留下你的评论吧~