从 Spring Boot 2 升到 3,我改了三天代码
起因
项目还在 2.7.x,本来没打算动。直到有天收到安全扫描报告,说某个依赖在 2.x 上已经不维护了,建议升到 3.x。查了一下,Spring Boot 2.7 的开源支持到 2024 年 11 月就结束了,再拖下去连安全补丁都没了。
行吧,升。原以为改改版本号的事,结果折腾了三天。
第一刀:javax 变 jakarta
这是最直观也最烦人的改动。所有 javax.servlet.*、javax.persistence.*、javax.validation.* 的 import,全要换成 jakarta.*。
项目里几百个文件,手动改不现实。IDEA 有个批量替换功能,但得小心:有些 javax 开头的包跟 Jakarta EE 没关系(比如 javax.crypto),不能一刀切。我是先全局搜 import javax.,筛出 servlet、persistence、validation、annotation 这几个前缀的,再批量替换。改完编译报错少了一大半,剩下的才是真正的坑。
第二刀:MyBatis-Plus 的隐藏地雷
项目用的是 MyBatis-Plus,升完 Spring Boot 3.2 之后启动直接报:
Invalid value type for attribute 'factoryBeanObjectType': java.lang.String
查了半天,问题是 MyBatis-Plus 自带的 mybatis-spring 版本太低,跟 Spring 6 的 Bean 创建流程不兼容。解决方式是把依赖坐标换掉:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
注意 artifactId 里多了 spring-boot3。不是简单升个版本号就行的,坐标本身变了。这个坑如果不看报错日志,光靠猜能卡一整天。
第三刀:Security 配置全废了
老项目里 WebSecurityConfigurerAdapter 用得飞起,Spring Security 6 直接把这个类删了。所有继承它的配置类编译都过不去。
改成注册 SecurityFilterChain Bean 的方式:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.csrf(csrf -> csrf.disable());
return http.build();
}
写法跟以前完全两个风格,lambda 链式调用,得对着文档一条条迁。好在配置类不多,改了两个小时弄完了。
第四刀:Swagger 用不了了
之前用的 SpringFox,在 Spring Boot 3 下根本不工作。查了一下,SpringFox 已经不再维护,社区方案是换 SpringDoc。
依赖换掉:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
注解也得跟着换。@Api 变 @Tag,@ApiOperation 变 @Operation,@ApiModelProperty 变 @Schema。Controller 和实体类上几百个注解,又是一个批量替换的活。好在大部分是一对一映射,对着对照表改就行,不用动脑子,但费眼睛。
第五刀:时间序列化,最隐蔽的一个
前四刀都是编译期报错,改完就能跑。这个不一样,启动正常,接口也能调,但前端传过来的时间字符串反序列化失败,直接 400。
报错是 DateTimeParseException: Text '2024-06-15T10:30:00' could not be parsed at index 10。原因是 Spring Boot 3 的 Jackson 配置变了,旧版自动适配的 LocalDateTimeDeserializer 在新版里默认不生效了。得手动在字段上加 @JsonFormat,或者在全局配置里注册自定义的序列化器。
我选了全局配置,在 ObjectMapper 里统一注册 JavaTimeModule,省得每个实体类都写注解。
顺带提一下 Lombok
如果用的是 JDK 17,Lombok 版本得跟上。我项目里原来的版本太低,编译时报 NoSuchFieldError,升到 1.18.30 才消停。如果是 JDK 21 的项目,还得更高。这个不算 Spring Boot 本身的问题,但升级时很容易撞上。
改完之后
启动时间从原来的十几秒变成了二十多秒,可能是新版本加了东西,也可能是我本地环境的问题,暂时没深究。功能跑了一遍,核心链路都通,时间格式和 Swagger 文档确认没问题之后才算收工。
回头看,最耗时的不是技术难点,是批量改动的体力活。javax 换 jakarta、Swagger 注解替换,都是机械操作,但量大了就容易漏。建议升级前先把项目里的 javax.* 和 SpringFox 注解数量统计一下,心里有个数。
另外,别一次全升。我是先升到 3.0.x 跑通,再升 3.2.x。跨大版本直接跳,报错会叠在一起,排查起来分不清哪个是哪个的问题。
先记这些。如果你的项目还在 2.7,趁早动手,越拖改的东西越多。
- 点赞
- 收藏
- 关注作者
评论(0)