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>