项目现状
组件 | 版本 | 备注 |
---|---|---|
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框架可能有一个核心模块,以及用于处理各种任务的可选模块(如数据库访问、缓存、身份验证等)。
-
Jakarta是Java生态系统中的一个命名空间 ,旨在为Java技术和规范提供一个开放、中立的基础。它由Java基金会的一个开源项目组成,提供了一系列的规范和参考实现,如Jakarta EE、Jakarta Persistence、Jakarta JSON、Jakarta Batch等。Jakarta的目的是为Java开发人员提供更加开放和中立的基础,使他们能够更轻松地构建高效、安全、可靠的应用程序。