一、背景與挑戰(zhàn)
1.升級(jí)動(dòng)因
?Oracle長(zhǎng)期支持策略
?現(xiàn)代特性需求:協(xié)程、模式匹配、ZGC等
?安全性與性能的需求
?AI新技術(shù)引入的版本要求
2.項(xiàng)目情況
?100+項(xiàng)目并行升級(jí)的協(xié)同作戰(zhàn)
?多技術(shù)棧并存
?持續(xù)集成體系的適配挑戰(zhàn)
?
二、進(jìn)度
| 應(yīng)用總數(shù) | 已完成 | 應(yīng)用下線 | 待升級(jí) |
| 100+ | 73 | 13 | 10+ |
?
三、主要問(wèn)題域與解決方案
1. 依賴管理的"蝴蝶效應(yīng)"
?sun.misc.BASE64Encoder等內(nèi)部API廢棄 → 引發(fā)編譯錯(cuò)誤
?JAXB/JAX-WS從JDK核心剝離 → XML處理鏈斷裂
?Lombok與新版編譯器兼容性問(wèn)題(尤其record類型)
核心原因在于JEP320提案:https://openjdk.org/jeps/320?
?
案例1:歷史SDK的編譯陷阱
Compilation failure: Compilation failure: #14 4.173 [ERROR] 不再支持源選項(xiàng) 6。請(qǐng)使用 8 或更高版本。 #14 4.173 [ERROR] 不再支持目標(biāo)選項(xiàng) 6。請(qǐng)使用 8 或更高版本。
!-- 舊版本編譯器配置導(dǎo)致構(gòu)建失敗 --?>
org.apache.maven.plugins/groupId?>
maven-compiler-plugin/artifactId?>
3.5/version?>
1.6/source?>
1.6/target?>
/configuration?>
/plugin?>
org.apache.maven.plugins/groupId?>
maven-compiler-plugin/artifactId?>
3.13.0/version?>
8/release?>!-- 統(tǒng)一使用release參數(shù) --?>
/configuration?>
/plugin?>
運(yùn)行 HTML
案例2:JAXB的模塊化剝離
javax.xml.bind.JAXBException:Implementation of JAXB-API has not been found
org.glassfish.jaxb/groupId?>
jaxb-runtime/artifactId?>
4.0.5/version?>
/dependency?>
案例3:Lombok與新版編譯器兼容性問(wèn)題
java: java.lang.NoSuchFieldError
org.projectlombok/groupId?> lombok/artifactId?> 1.18.30/version?> /dependency?>
案例4:Resource注解找不到
Caused by: java.lang.NoSuchMethodError: 'java.lang.String javax.annotation.Resource.lookup()' at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.(CommonAnnotationBeanPostProcessor.java:664) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.lambda$buildResourceMetadata$0(CommonAnnotationBeanPostProcessor.java:395) at org.springframework.util.ReflectionUtils.doWithLocalFields(ReflectionUtils.java:669) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.buildResourceMetadata(CommonAnnotationBeanPostProcessor.java:377) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.findResourceMetadata(CommonAnnotationBeanPostProcessor.java:358) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(CommonAnnotationBeanPostProcessor.java:306) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:1116) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ... 37 more
jakarta.annotation/groupId?>
jakarta.annotation-api/artifactId?>
1.3.5/version?>
/dependency?>
javax.annotation/groupId?>
javax.annotation-api/artifactId?>
1.3.2/version?>
/dependency?>
上述兩個(gè)依賴代碼基本一樣,推薦使用該版本:
jakarta.annotation:jakarta.annotation-api。
?
2. 模塊化的破與立
反射訪問(wèn)的模塊墻
[ERROR] Unable to make field private int java.text.SimpleDateFormat.serialVersionOnStream accessible
# 啟動(dòng)參數(shù)添加模塊開(kāi)放配置 --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED
完整模塊開(kāi)放配置模板
export JAVA_OPTS="-Djava.library.path=/usr/local/lib -server -Xmx4096m --add-opens java.base/sun.security.action=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/sun.util.calendar=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED --add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.management/java.lang.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens java.base/sun.security.action=ALL-UNNAMED --add-opens java.base/sun.net.util=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED"
3. 語(yǔ)法層面的"時(shí)空穿越"
案例1:Base64編解碼改造
// JDK8寫(xiě)法(已廢棄) BASE64Encoder encoder =newBASE64Encoder(); String encoded = encoder.encode(data); // JDK21規(guī)范寫(xiě)法 Base64.Encoder encoder =Base64.getEncoder(); String encoded = encoder.encodeToString(data);
案例2:日期序列化問(wèn)題
Caused by:java.lang.reflect.InaccessibleObjectException: Unable to make field private int java.text.SimpleDateFormat.serialVersionOnStream accessible
解決方案
1.使用DateTimeFormatter替代SimpleDateFormat
2.或添加模塊開(kāi)放參數(shù):--add-opens java.base/java.text=ALL-UNNAMED
?
4. 隱秘的"依賴戰(zhàn)爭(zhēng)"
注解包沖突典型案例
[ERROR] javax.annotation.Resource exists in both jsr250-api-1.0.jar and jakarta.annotation-api-1.3.5.jar
!-- 統(tǒng)一使用Jakarta標(biāo)準(zhǔn) --?>
jakarta.annotation/groupId?>
jakarta.annotation-api/artifactId?>
2.1.1/version?>
/dependency?>
!-- 排除舊版本依賴 --?>
javax.annotation/groupId?>
jsr250-api/artifactId?>
/exclusion?>
/exclusions?>
5. 構(gòu)建體系的改造
Maven插件兼容性問(wèn)題
[ERROR] The plugin org.apache.maven.plugins:maven-compiler-plugin:3.13.0 requires Maven version 3.6.3
升級(jí)策略
1.升級(jí)Maven版本
2.統(tǒng)一插件版本
org.apache.maven.plugins/groupId?>
maven-compiler-plugin/artifactId?>
3.13.0/version?>
/plugin?>
org.apache.maven.plugins/groupId?>
maven-war-plugin/artifactId?>
3.4.0/version?>
/plugin?>
/plugins?>
/pluginManagement?>
/build?>
四、最佳實(shí)踐總結(jié)
1. 本地編譯
第一步:在本地進(jìn)行編譯,提前識(shí)別出語(yǔ)法錯(cuò)誤、版本沖突及不兼容問(wèn)題。
主要有以下幾種場(chǎng)景:
Base64:參照 【Base64編解碼改造】
lombok:升級(jí)版本
jsr250、jaxb-runtime、jakarta.annotation-api:參照 【注解包沖突典型案例】
maven-compiler-plugin:升級(jí)版本
maven-resources-plugin:升級(jí)版本
maven-war-plugin:升級(jí)版本
?
?
2. 行云構(gòu)建
同【本地編譯】
?
3. 行云部署
a、鏡像不匹配:自定義鏡像或者使用已申請(qǐng)的jdk21鏡像
b、module權(quán)限不夠:參照【完整模塊開(kāi)放配置模板】
c、JDSecurity加解密
所有數(shù)據(jù)庫(kù)操作:important.properties配置文件的處理方式
classpath:important.properties 使用PropertyPlaceholderConfigurer進(jìn)行處理,不要用JDSecurityPropertyFactoryBean。
!-- --?> !-- --> !-- --> !-- /bean?>-->
?
4. 運(yùn)行
a、序列化異常
jdk21使用列表視圖作為入?yún)ⅲ瑢?dǎo)致jsf接口進(jìn)行反序列化報(bào)錯(cuò)。報(bào)錯(cuò)代碼如下:
List subList = venderCodes.subList(i * batchSize, Math.min(venderCodes.size(), (i + 1) * batchSize)); VendorQueryVo vendorQueryVo = new VendorQueryVo(); vendorQueryVo.setVendorCodes(subList); // 該接口最多支持100條調(diào)用 List batchVendorNameByVendorCode = vendorBaseInfoService.getBatchVendorNameByVendorCode(vendorQueryVo, I18NParamFactory.getJDI18nParam());
將 vendorQueryVo.setVendorCodes(subList) 修改為vendorQueryVo.setVendorCodes(new ArrayList<>(subList)) 即可解決問(wèn)題
?
b、線程上下文類找不到:使用多線程場(chǎng)景下盡可能使用顯式指定線程池【默認(rèn)情況下 不同運(yùn)行環(huán)境的處理機(jī)制不同】
?
?
5. JVM調(diào)優(yōu)
垃圾回收調(diào)優(yōu)
UseParallelGC、UseG1GC和UseZGC是 Java 虛擬機(jī)(JVM)中三種不同的垃圾回收器(Garbage Collector, GC),它們的設(shè)計(jì)目標(biāo)和使用場(chǎng)景有所不同。以下是它們的區(qū)別:
| 特性 | UseParallelGC | UseG1GC | UseZGC |
| 設(shè)計(jì)目標(biāo) | 高吞吐量 | 平衡吞吐量和延遲 | 極低延遲 |
| 暫停時(shí)間 | 較長(zhǎng) | 較短 | 極短 |
| 適用堆大小 | 中小堆(幾 GB 到幾十 GB) | 大堆(幾十 GB 到幾百 GB) | 超大堆(TB 級(jí)別) |
| CPU 消耗 | 中等 | 中等 | 較高 |
| 適用場(chǎng)景 | 批處理、計(jì)算密集型任務(wù) | 對(duì)延遲有一定要求的應(yīng)用 | 對(duì)延遲極其敏感的應(yīng)用 |
?如果你的應(yīng)用對(duì)吞吐量要求高,且可以接受較長(zhǎng)的暫停時(shí)間,選擇UseParallelGC。
?如果你的應(yīng)用對(duì)延遲有一定要求,且堆內(nèi)存較大,選擇UseG1GC。
?如果你的應(yīng)用對(duì)延遲極其敏感,且堆內(nèi)存非常大,選擇UseZGC。
僅供參考,具體請(qǐng)按照實(shí)際情況來(lái)進(jìn)行調(diào)整。
審核編輯 黃宇
-
JDK
+關(guān)注
關(guān)注
0文章
83瀏覽量
17189
發(fā)布評(píng)論請(qǐng)先 登錄
為什么OCPP充電樁Security Profile要升級(jí)到2/3?
深圳南柯電子|新能源電子EMC整改:從技術(shù)攻堅(jiān)到產(chǎn)業(yè)升級(jí)的工程
V5.0.0 ps 打印顯示線程 error 狀態(tài)全為 EINTRPT,,為什么?
明遠(yuǎn)智睿RK3568核心板如何助力工業(yè)4.0升級(jí)
從“代步工具”到“智能伙伴”,存儲(chǔ)如何支撐汽車升級(jí)之路
從 400G 升級(jí)到 800G,到底能省多少錢(qián)?(洞察 TCO 真相)
從Modbus到Profinet:功率表通信升級(jí)的技術(shù)挑戰(zhàn)與解決方案
從舊款升級(jí)到樹(shù)莓派5,你必須注意的幾個(gè)問(wèn)題!
STM32MP157d linux從5.4.31升級(jí)到6.1.82無(wú)法啟動(dòng)怎么解決?
STM32MP157d linux從5.4.31升級(jí)到6.1.82無(wú)法啟動(dòng)怎么解決?
STM32MP157d linux從5.4.31升級(jí)到6.1.82無(wú)法啟動(dòng)怎么解決?
XT大升級(jí) 加量不加價(jià)|Amass LC2.0升級(jí)版新品連接器破界而來(lái)
JDK從8升級(jí)到21的問(wèn)題集
評(píng)論