JDK 8 升级 JDK 17
首先已有项目升级是会经历一个较长的调试和自测过程来保证允许和兼容没有问题。先说几个重要的点
- 遇到问题别放弃
- 仔细阅读报错,精确到每个单词每一行,不是自己项目的代码也要点进去看看源码到底是为啥报错
- 明确你项目引入的包,升级到 JDK17 后对应低版本的都需要升级
可能大部分同学都不是完全了解自己的项目都依赖了什么包,这个升级工作一定会加深你对 maven 包管理的理解,以及你对你项目依赖的熟悉程度和你解决排查问题的能力。
项目跑不起来就慢慢调试,问题暂时解决不了就放一放,放松一下,交给下个阶段头脑清醒的自己。
升级你的 maven 编译版本
修改你主工程的 pom 文件
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>17</source><target>17</target></configuration>
</plugin>
我用的是 idea 修改你项目的编译环境
从新拉 maven 之后你就可以看看哪里报红哪里需要改了,别担心,噩梦才刚刚开始哈哈哈
去除重复依赖
长时间的维护,可能存在一个包在一个 pom 里引入两次的情况 (真服了)
首先项目中 pom 文件不可以出现重复依赖,需要排查去掉
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId>
</dependency>
对于依赖版本,不可以直接出现 RELEASE,你可以定义一个 properties 然后引用一下
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>RELEASE</version><scope>test</scope>
</dependency>
一些依赖的版本升级
这部分只列举我再升级过程中遇到的需要升级的问题
升级 lombok 到 1.18.26
lombok 得用新版本 我之前是 1.18.4 现在换到 26
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version>
</dependency>
升级 springboot 到 2.7.14
你可以在官方文档看到 2.7.14 对应的一些依赖版本
https://docs.spring.io/spring-boot/docs/2.7.14/reference/html/dependency-versions.html#appendix.dependency-versions
<spring.boot.version>2.7.14</spring.boot.version>
<spring.version>5.3.29</spring.version>
<dubbo.version>2.7.23</dubbo.version>
说一下我这里为什么没有选择拥抱 3.x ,因为 dubbo 3 才支持 springboot 3.x 和 spring6.x,而我调用的三方接口都是 dubbo2,dubbo3 应用基本注册不向下兼容 dubbo2,会有诸多问题,所以这里选择
2.7.14 GA 这个官网稳定支持的版本,如果你没有这个问题,可以选择拥抱 3.0
提醒一下如果要升级 springboot3
springboot3 弃用了 javax.servlet.http.HttpServletRequest; 需要替换为 jakarta.servlet.http.HttpServletRequest;
HandlerInterceptorAdapter 被删除了,由 HandlerInterceptor 来代替
yml 配置允许循环依赖
spring:main:allow-circular-references: true
三方包依赖找不到类
我引入的三方包,Spring bean 加载存在问题,感觉是 JDK 升级的问题,跟 spring 的升级没关系
是找不到这个玩意的定义 org.apache.commons.configuration.interpol.ConfigurationInterpolator
nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.apache.commons.configuration.interpol.ConfigurationInterpolator
很怪,明明有就找不到,这里将三方包的引入排除掉,自己项目中单独进行引入
<exclusion><artifactId>commons-configuration</artifactId><groupId>commons-configuration</groupId>
</exclusion><dependency><groupId>commons-configuration</groupId><artifactId>commons-configuration</artifactId><version>1.10</version>
</dependency>
顺便提一个 springbean 加载的问题,如果你引入的三方包有路径下的 bean 需要你进行注册管理,你项目启动类的扫描路径下需要包含他的路径,比如
@SpringBootApplication(scanBasePackages = {"com.你的包","com.三方的需要扫描的包路径"})
当然,如果路径一致,就一个就可以
zookeeper 升级 3.5.10
升级 zookeeper 版本为 3.5.10 , 3.5.x 以下不兼容 JDK17
https://curator.apache.org/zk-compatibility-34.html 还有个 curator 强依赖的场景需要注意升级
如果你服务器的 zookeeper 可以升级最好不过,如果不能
curator 2.x 可以兼容 zookeeper 3.5.x 的版本
如果你之前使用的是 curator 2.x 就只升级 zookeeper 的版本就行了,这样连接你线上的 zookeeper 不会有问题。
否则请将服务器版本同步升级
可参考文章:
官方文章 https://curator.apache.org/zk-compatibility-34.html
csdn 文章 https://blog.csdn.net/wo541075754/article/details/69138878
<apache-curator.version>2.12.0</apache-curator.version>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>${apache-curator.version}</version><exclusions><exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>${apache-curator.version}</version><exclusions><exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions>
</dependency>
mysql 版本升级 8.0.33
没啥好说的,不升你连不上
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version>
</dependency>
启动项
注意你项目启动时需要增加启动参数,不管是实际运行还是本地调试运行
--add-opens
java.base/java.lang=ALL-UNNAMED
--add-opens
java.base/java.io=ALL-UNNAMED
--add-opens
java.base/java.math=ALL-UNNAMED
--add-opens
java.base/java.net=ALL-UNNAMED
--add-opens
java.base/java.nio=ALL-UNNAMED
--add-opens
java.base/java.security=ALL-UNNAMED
--add-opens
java.base/java.text=ALL-UNNAMED
--add-opens
java.base/java.time=ALL-UNNAMED
--add-opens
java.base/java.util=ALL-UNNAMED
--add-opens
java.base/JDK.internal.access=ALL-UNNAMED
--add-opens
java.base/JDK.internal.misc=ALL-UNNAMED
当然你如果不加也能起可以不加。解释一下
--add-opens
参数是在 JDK 9 及更高版本中引入的,用于在模块系统中打开特定的包以实现反射访问。模块系统引入了更严格的访问控制,以确保代码的可靠性和安全性。在某些情况下,一些库或框架可能依赖于 JDK 内部的类和方法,这些类和方法在模块系统中是受限的,因此需要通过 --add-opens
参数进行显式打开。
具体来说,--add-opens
参数允许你在指定的模块中打开某个包,以便其他模块可以通过反射访问该包中的类和方法。java.base
是 JDK 的基础模块,其中包含了 Java 核心类库。使用 --add-opens java.base/java.lang=ALL-UNNAMED
参数是为了在 JDK 9 及更高版本中允许在 java.base
模块中的 java.lang
包中打开所有未命名的类,从而允许反射访问。
通常情况下,如果你的应用代码遵循良好的编程实践,是不需要使用 --add-opens
参数的。然而,一些第三方库、框架或老旧的代码可能会依赖于 JDK 内部的特性,这时可能会需要使用这个参数来解决访问限制问题。不过,尽量避免在生产环境中过度依赖这种方式,因为这可能会引入一些潜在的风险和不稳定性。
比如
import sun.misc.Unsafe;public class RestrictedAccessExample {public static void main(String[] args) {try {// 使用反射获取 Unsafe 类的实例Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");Unsafe unsafe = (Unsafe) unsafeClass.getDeclaredField("theUnsafe").get(null);// 使用 Unsafe 实例调用内部方法long value = 42;long address = unsafe.allocateMemory(8);unsafe.putLong(address, value);System.out.println("Value at address: " + unsafe.getLong(address));} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();}}
}
全部启动项示例
当然你之前的垃圾回收器可能还在用 CMS ,那已经废弃了,所以需要改,用 G1 或者 ZGC 吧,这里我推荐直接用 ZGC。
ZGC 在 17 中已经非常成熟
-Xms2G -Xmx2G -XX:MaxDirectMemorySize=256M -XX:ThreadStackSize=512 -XX:MaxMetaspaceSize=256M -XX:MetaspaceSize=256M -XX:-OmitStackTraceInFastThrow -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:ZAllocationSpikeTolerance=5 -Xlog:gc:/logs/gc.log
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/jdk.internal.access=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -jar dyinggq.jar
详细参数配置根据自己服务自行适配调整。
报错集
这里收录一下报错和解决方案
nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.apache.commons.configuration.interpol.ConfigurationInterpolator
这个找不到类,找到对应的调用位置,看看为啥没有。最后解决方案是排除了三方包的引入,自行单独引入该包
<exclusion><artifactId>commons-configuration</artifactId><groupId>commons-configuration</groupId>
</exclusion><dependency><groupId>commons-configuration</groupId><artifactId>commons-configuration</artifactId><version>1.10</version>
</dependency>
这个报错是你 zookeeper 的客户端包版本不兼容你服务器的版本
Caused by: java.lang.IllegalStateException: KeeperErrorCode = Unimplemented for org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.createEphemeral(CuratorZookeeperClient.java:114)at org.apache.dubbo.remoting.zookeeper.AbstractZookeeperClient.create(AbstractZookeeperClient.java:83)at org.apache.dubbo.registry.zookeeper.ZookeeperRegistry.doRegister(ZookeeperRegistry.java:125)... 77 common frames omitted
这里是因为我当时升级 zookeeper 的时候 curator 也一起升到 3.x 了,而线上服务 zookeeper 的版本是 3.4.x
<apache-curator.version>2.12.0</apache-curator.version>
所以 curator 还用老版本
dubbo No such extension cid for loadbalance/org.apache.dubbo.rpc.cluster.LoadBalanced
dubbo 找不到自定义的 Balance ,这个有很多情况,我说我的情况,我的情况是项目服务还在使用
com.alibaba.dubbo ,然后我想一起升级到 org.apache.dubbo ,结果找不到了,想来是路径的问题,老的都是继承的
com.alibaba.dubbo .rpc.cluster.LoadBalanced
你升级了需要org.apache.dubbo.rpc.cluster.LoadBalanced
这个如果你依赖三方包的,还真改不了,好在,之前版本的 dubbo 也能在 jdk17 下运行。
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut aspect
这个是 aspectj 版本不匹配
排除其他包引入的 aspecj 引入对应 springboot 版本的 aspecj ,我这里给的是 springboot 2.7.14 对应的
<aspectjweaver.version>1.9.7</aspectjweaver.version>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>${aspectjweaver.version}</version>
</dependency>