升级springboot2.7.10项目到jdk21&springboot3.1.15

项目现状

组件 版本 备注
java 1.8 准备升级到jdk 21
springboot 2.7.10 不更新:准备先用这个版本适配jdk 21
lombok 1.16.16 java版本发生变化,此处可能要升级
maven-compiler-plugin 3.10.1 初步判断,不用更新
maven-resources-plugin 3.2.0 初步判断,不用更新

升级策略

经过多轮思考,准备先用springboot2.7.10+jdk 21组合来实现第一轮升级,成功后再将springboot从2.7.10升级到3.1.5。

第一轮升级springboot2.7.10+jdk 21

  • 将项目的jdk版本从1.8修改为21
  • 将根pom中的重要组件升级

在刚开始时,我们只升级java.version为21,然后使用IntelliJ IDEA进行编译,遇到问题

Unable to make field private com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors com.sun.tools.javac.processing.JavacProcessingEnvironment.discoveredProcs accessible: module jdk.compiler does not "opens com.sun.tools.javac.processing" to unnamed module @4451f60c

然后各种尝试后,我们选择放弃使用IntelliJ IDEA进行编译,转而使用mvn命令行进行编译。

OK。尝试用mvn进行编译,遇到如下问题:

问题:Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field 'com.sun.tools.javac.tree.JCTree qualid'

解决办法:将lombok从1.16.16升级到1.18.30

升级后,再尝试编译,正常了。

ini 复制代码
# 编译模块xxx
mvn clean compile -am -pl xxx-search
# 打包模块xxx
mvn clean package -am -pl xxx-search -DskipTests -Pvue,qc

# 运行模块方式一
java -jar --spring.profiles.active=qc ./xxx-search/target/xxx-search-1.0.0.jar

# 运行模块方式二
mvn spring-boot:run -am -pl xxx-search -Pprd,vue  -Dspring-boot.run.profiles=qc  -Dspring-boot.run.jvmArguments="-Dserver.port=8189 -Dspring.profiles.active=qc -Xmx2g -Xms2g"

最终发现,升级还是比较简单的,只需要升级java和lombok版本即可,最终的版本表格如下所示。

组件 升级前的版本 升级后的版本 备注
java 1.8 21 升级到jdk21
springboot 2.7.10 不变
lombok 1.16.16 1.18.30 升级到1.18.130
maven-compiler-plugin 3.10.1 不变
maven-resources-plugin 3.2.0 不变
mysql-connector-j 6.0.6 8.1.0 估计此处本可以不升级,顺手就升了
druid-spring-boot-starter 1.1.10 1.2.20 估计此处本可以不升级,顺手就升了
mybatis-spring-boot-starter 1.2.0 2.3.1 估计此处本可以不升级,顺手就升了,此处注意: 它现在有2.x和3.x。springboot2.x可以使用2.x,但不能使用3.x。

使用mvn spring-boot:run时,遇到提示Unable to find a suitable main class, 原因是它在尝试运行根pom项目。这需要在根pom中配置跳过, 在非根pom项目中配置不跳过。

xml 复制代码
# 根pom
<plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>
    </plugins>
</build>

非根pom项目
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <skip>false</skip>
                <!--<fork>true</fork>-->
            </configuration>
        </plugin>
        
### 最后注意不能配置fork,配置后会开新的进程进行构建,会导致我们在控制台就看不到输出了,
### 因此不需配置此项fork=true。

第二轮升级springboot2.7.10+jdk 21 到springboot3.1.15+jdk 21

在这轮升级,我们发现主要是springboot3的一些变化。比如我们的项目遇到下面两个问题。

问题1:springboot3中移除了WebMvcConfigurerAdapter,导致此问题出现

class path resource [org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.class] cannot be opened because it does not exist

问题2:spring-context-support:6.0.13移除了ehcache

问题3:缺少java包,比如javax.annotation.Resource;

需要添加依赖

kotlin 复制代码
javax.annotation:javax.annotation-api:1.3.1

问题4: 找不到javax.servlet.http.HttpServletRequest

移除javax.servlet-api, 将javax.servlet.http.HttpServletRequest 换成jakarta.servlet.http.HttpServletRequest

xml 复制代码
# 注释掉依赖项javax.servlet-api
 <!--<dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <scope>provided</scope>
    </dependency>-->
</dependencies>

问题5:在编译时,提示maven-resource plugin InputLength问题,经过加上-X 发现在filtering时,遇到了swf,zip,db这种二进制文件时出了问题。因此先在nonFilteredFileExtensions中增加这些后缀进行排查。

问题6:由于在基础模块core中将lombok改成scope=provided,导致此依赖无法传播到其他模块,因此需要将lobok依赖加在所有需要的模块中。

充分理解问题进行修改复后,再尝试编译,正常了。

ini 复制代码
# 编译模块xxx
mvn clean compile -am -pl xxx-search

# 打包模块xxx
mvn clean package -am -pl xxx-search -DskipTests -Pvue,search-qc

# 运行模块方式一
java -jar --spring.profiles.active=qc ./xxx-search/target/xxx-search-1.0.0.jar

# 运行模块方式二
mvn spring-boot:run -am -pl xxx-search -Pprd,vue -Dspring-boot.run.profiles=qc  -Dspring-boot.run.jvmArguments="-Dserver.port=8189 -Dspring.profiles.active=qc -Xmx2g -Xms2g"

使用方式二mvn spring-boot:run -am -pl运行效果如下,我们发现这种mvn spring-boot:run输出的信息更加丰富,更有利于我们理解spring-boot的工作原理。

使用Ctrl+C终止应用运行,我们发现有以下事件触发,见下图

总结

因为我们的项目本身使用的是较高的springboot版本(2.7.10),因此整体上升级过程比较顺利。在升级过程中我们发现IntelliJ IDEA 2021.3.3无法编译jdk21应用,因此我们选择了使用java命令行来编译。

在升级jdk21时,主要关注lombok, mapstruct, maven-compile-plugin, maven-resources-plugin这些插件的版本和兼容性即可,整体感觉还是有坎坷。最终感受还是很顺滑,推荐升级,迈开前进的第一步。

如果你的项目是低版本的spring-boot或spring-cloud项目,可能涉及到的组件更新更多,比如要涉及升级junit5, swagger/knife4j等等。

参考资料

只有当依赖的 scope 标签被定义为 compile 时才会发生依赖传递,而定义为 test \provided\runtime 都不会发生依赖传递。

场景1:降低库的依赖传递 假设我们正在开发一个名为library-a的库,它依赖于另一个名为library-b的库。然而,library-b有一些我们并不需要的依赖项。为了避免这些不必要的依赖项传递给使用library-a的项目,我们可以将它们设置为可选。

场景2:提供可插拔的功能 在某些情况下,我们可能希望提供一个具有可插拔功能的库。例如,一个日志库可能支持多种日志框架,但我们希望让用户选择他们要使用的框架,而不是强制将所有可能的依赖项包含在构建中。

场景3:支持可选的扩展模块 在一些项目中,我们可能希望建立一个核心库,并提供一系列可选的扩展模块。例如,一个Web框架可能有一个核心模块,以及用于处理各种任务的可选模块(如数据库访问、缓存、身份验证等)。

相关推荐
会说法语的猪1 小时前
springboot实现图片上传、下载功能
java·spring boot·后端
凡人的AI工具箱1 小时前
每天40分玩转Django:实操多语言博客
人工智能·后端·python·django·sqlite
Cachel wood2 小时前
Django REST framework (DRF)中的api_view和APIView权限控制
javascript·vue.js·后端·python·ui·django·前端框架
m0_748234082 小时前
Spring Boot教程之三十一:入门 Web
前端·spring boot·后端
想成为高手4992 小时前
国产之光--仓颉编程语言的实战案例分析
后端
编码浪子3 小时前
构建一个rust生产应用读书笔记7-确认邮件2
开发语言·后端·rust
昙鱼3 小时前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
白宇横流学长3 小时前
基于SpringBoot的停车场管理系统设计与实现【源码+文档+部署讲解】
java·spring boot·后端
kirito学长-Java3 小时前
springboot/ssm太原学院商铺管理系统Java代码编写web在线购物商城
java·spring boot·后端
程序猿-瑞瑞3 小时前
24 go语言(golang) - gorm框架安装及使用案例详解
开发语言·后端·golang·gorm