日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

1、前言

 

上篇文章給大家帶來了 JDK8 升級 JDK11 的最全實踐,相信大家閱讀后已經對 JDK11 有了比較深入的了解。2021 年 9 月 14 日,Oracle 發布了可以長期支持的 JDK17 版本,那么從 JDK11 到 JDK17,到底帶來了哪些特性呢?亞毫秒級的 ZGC 效果到底怎么樣呢?值得我們升級嗎?而且升級過程會遇到哪些問題呢?帶著這些問題,本篇文章將帶來完整的 JDK11 升級 JDK17 最全實踐。

2、為什么升級 JDK17

1)長期支持版本

JDK17 是 Oracle 官方在 2021 年 9 月 14 日發布的一個長期支持(LTS)版本,意味著它將獲得長期的更新和支持,有助于保持程序的穩定性和可靠性。

2)性能提升

更好的垃圾回收器。綜合評估,從 JAVA 8 升級到 Java 11,**G1GC 平均速度提升 16.1%,ParallelGC 為 4.5%****,** 從 Java 11 升級到 Java 17,G1GC 平均速度提升 8.66%,ParallelGC 為 6.54%(基于 OptaPlanner 的用例基準測試表明)

最大的亮點是帶來了穩定版的 ZGC 垃圾回收器,達到亞毫秒級停頓。

3)新語法和特性

Switch 表達式簡化、Text Blocks 文本塊、instanceof 的模式匹配升級和 NullPointerException 提示信息改進等

4)支持最新的技術和框架

Spring framework6 和 Spring Boot3 都默認使用 Java 17 作為最低版本

3、升級后壓測效果

先給出結論:
1、JDK17 相對于 JDK8 和 JDK11, 所有垃圾回收器的性能都有很明顯的提升,特別是穩定版的 ZGC 垃圾回收器
2、 不論任何機器配置下,都推薦使用 ZGC,ZGC 的停頓時間達到亞毫秒級,吞吐量也比較高

我在 JDOS 平臺上選擇了不同配置的機器(2C4G、4C8G、8C16G),并分別使用 JDK8、JDK11 和 JDK17 進行部署和壓測。

整個壓測過程限時 60 分鐘,用 180 個虛擬用戶并發請求一個接口,每次接口請求都創建 512Kb 的數據。最終產出不同 GC 回收器的各項指標數據,來分析 GC 的性能提升效果。

以下是壓測的性能情況:

JDK11 升級 JDK17 最全實踐干貨來了

4、OracleJDK 和 OpenJDK 的選擇

2021 年 9 月,Oracle 宣布 JDK17 可以免費商用,直到下一個 LTS 版本之后繼續提供整整一年,同時 Oracle 將繼續按照自 Java 9 以來的相同版本和時間表提供 GPL 下的 Oracle OpenJDK 版本。

2023 年 9 月,OracleJDK 發布了新的 LTS 版本 JDK21,這就意味著從 2024 年 9 月開始,在生產環境使用 OracleJDK17 將需要付費。

JDK11 升級 JDK17 最全實踐干貨來了

參考: https://www.oracle.com/hk/java/technologies/downloads/#java17

OracleJDK 和 OpenJDK 這兩個之間沒有真正的技術差別,因為針對 Oracle JDK 構建過程是基于 OpenJDK 的。自從 JDK11 開始,OracleJDK 和 OpenJDK 在功能上基本相同,所以推薦使用 OpenJDK17 或其他開源的 JDK 版本,這些開源版本都是基于 OpenJDK 構建并提供長期支持的,比如:AdoptOpenJDK、RedHatOpenJDK。

JDK11 升級 JDK17 最全實踐干貨來了

官方參考: https://blogs.oracle.com/java/post/oracle-jdk-releases-for-java-11-and-later

5、JDK11 到 JDK17 帶來了哪些新特性

5.1、JVM 改進

1、ZGC 垃圾回收器從實驗性功能更改為正式產品功能,從 JDK11 引入以來,經過持續的迭代升級,目前已經足夠穩定。需要手動開啟,開啟方式:-XX:+UseZGC

2、G1 垃圾回收器仍然作為默認垃圾回收器,進行改進升級,主要包括可中止的混合收集集合、NUMA 可識別內存分配等

3、JDK14 開始刪除 CMS 垃圾回收器

4、JDK14 開始棄用 ParallelScavenge 和 SerialOld GC 的組合使用

5、JDK15 禁用偏向鎖,默認禁用:-XX:+UseBiasedLocking

6、NullPointerException 提示信息改進

JDK14 以前的出現 NullPointerException 時,只能定位到所在異常行,無法定位具體是哪個變量。改進后的 NullPointerException,可以清晰描述具體變量,提升了空指針異常的可讀性。

JDK11 升級 JDK17 最全實踐干貨來了

5.2、新語法特性

5.2.1、Switch 表達式簡化

switch 表達式帶來了簡化式的編碼方式,提供了新的分支切換方式,即 -> 符號,右則表達式方法體在執行完分支方法之后,自動結束 switch 分支,同時 -> 右則方法塊中可以是表達式、代碼塊或者是手動拋出的異常

參考: https://openjdk.org/jeps/361

傳統寫法

JDK11 升級 JDK17 最全實踐干貨來了

新寫法

JDK11 升級 JDK17 最全實踐干貨來了

5.2.2、Text Blocks 文本塊

參考: https://openjdk.org/jeps/378

通過編寫 """,來減少轉義字符和換行符,達到簡化代碼和提高代碼可讀性的目的

JDK11 升級 JDK17 最全實踐干貨來了

5.2.3、Record 類型

參考: https://openjdk.org/jeps/395

record 是 JDK 14 引入的關鍵字,用于聲明不可變的數據類。它適用于存儲純粹的值類型數據,如接口傳輸數據、坐標點和只讀的日志記錄。與 lombok 相比,record 簡化了定義純粹數據類型的過程。由于 record 類是不可變的,成員變量只能設置一次且無法更改,無需提供顯式的 setter () 方法。

1、定義 Point 類,使用關鍵字 record,未定義 get/set

JDK11 升級 JDK17 最全實踐干貨來了

2、查看編譯后的字節碼文件

JDK11 升級 JDK17 最全實踐干貨來了

JDK11 升級 JDK17 最全實踐干貨來了

3、使用 Point 類

JDK11 升級 JDK17 最全實踐干貨來了

5.2.4、instanceof 的模式匹配升級

  • instanceof 類型判斷再也不需要強制轉換

參考: https://openjdk.org/jeps/394

JDK11 升級 JDK17 最全實踐干貨來了

5.2.5、密封的類和接口

參考: https://openjdk.org/jeps/409

JDK15 開始,引入了 sealed 普通類或接口類,這些類只允許被指定的類或者 interface 進行擴展和實現。

使用修飾符 sealed,您可以將一個類聲明為密封類。密封的類使用關鍵字 permits 列出可以直接擴展它的類。子類可以是最終的,非密封的或密封的

比較實用的一個特性,可以用來限制類的層次結構

JDK11 升級 JDK17 最全實踐干貨來了

5.2.6、其他優化和升級

感興趣的同學,推薦閱讀 OpenJDK 官方文檔說明,從 JDK11 到 JDK17 的改動: https://openjdk.org/projects/jdk/17/jeps-since-jdk-11

6、升級步驟

6.1、JDK 選擇

OpenJDK17 下載:https://jdk.java.NET/archive/

行云鏡像:jdt-base-Tomcat/java-jdt-centos7.4-openjdk-17.0.2-tomcat8.0.53

6.2、pom 編譯配置升級

maven 編譯所需 JDK 升級至 17

<properties>

<maven.compiler.source>17</maven.compiler.source>

<maven.compiler.target>17</maven.compiler.target>

</properties>

6.3、SpringBoot 升級

SpringBoot 版本升級到 2.7.15,Spring 版本升級為 5.3.29

為什么不升級到 SpringBoot3?

Spring Boot 3.0 最低要求 Java 17,SpringBoot3.0 帶來了很多變化,和 SpringBoot2 差異較大。 考慮到公司很多中間件都是基于 SpringBoot2 構建的,所以此處推薦升級到 SpringBoot2 的最高版本 2.7.15。

POM 升級

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.7.15</version>

</parent>

也可以通過設置 dependencyManagement 的方式:

<properties>

<!-- 框架版本配置-->

<springboot-version>2.7.15</springboot-version>

<springframework.version>5.3.29</springframework.version>

</properties>

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>${springboot-version}</version>

<scope>import</scope>

<type>pom</type>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-framework-bom</artifactId>

<version>${springframework.version}</version>

<scope>import</scope>

<type>pom</type>

</dependency>

</dependencies>

</dependencyManagement>

參考:

spring 升級指南: https://Github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions

springboot 版本官網: https://spring.io/projects/spring-boot#learn

循環依賴問題

SpringBoot 升級到 2.7.15 后,如果應用中存在循環依賴的問題,啟動時會報如下錯誤:

JDK11 升級 JDK17 最全實踐干貨來了

原因:官方文檔不鼓勵循環依賴引用,默認情況下是禁止的

解決方案:

第一種:推薦更新應用中 bean 的依賴關系來解決

第二種:配置文件中加入以下配置,為了和舊版本保持一致,此配置推薦添加

#放開循環依賴

spring.mAIn.allow-circular-references=true

6.4、常用中間件升級

6.4.1、Lombok 版本升級到 1.18.20 以上

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>1.18.20</version>

</dependency>

如果不升級,編譯時會報錯如下:

JDK11 升級 JDK17 最全實踐干貨來了

6.4.2、swgger 問題,springfox3.0.0 和 springboot2.7 版本不兼容

異常:

Failed to start bean 'documentationPluginsBootstrApper'; nested exception is java.lang.NullPointerException:

Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null

解決方案:

/**

* 增加如下配置可解決Spring Boot 2.7.15 與Swagger 3.0.0 不兼容問題

**/

@Bean

public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {

return new BeanPostProcessor() {

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {

customizeSpringfoxHandlerMappings(getHandlerMappings(bean));

}

return bean;

}

private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {

List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null).collect(Collectors.toList());

mappings.clear();

mappings.addAll(copy);

}

@SuppressWarnings("unchecked")

private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {

try {

Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");

field.setAccessible(true);

return (List<RequestMappingInfoHandlerMapping>) field.get(bean);

} catch (IllegalArgumentException | IllegalAccessException e) {

throw new IllegalStateException(e);

}

}

};

}

參考:https://developer.aliyun.com/article/950787

6.4.3、AKS 升級(針對直接從 JDK8 升級的情況)

異常:Causedby: java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

原因:Java11 刪除了 Java EE modules,其中就包括 java.xml.bind (JAXB)。

解決方案:

手動引入如下包即可

<!-- API, java.xml.bind module -->

<dependency>

<groupId>jakarta.xml.bind</groupId>

<artifactId>jakarta.xml.bind-api</artifactId>

<version>2.3.2</version>

</dependency>

<!-- Runtime, com.sun.xml.bind module -->

<dependency>

<groupId>org.glassfish.jaxb</groupId>

<artifactId>jaxb-runtime</artifactId>

<version>2.3.2</version>

</dependency>

6.4.4、Concrete 配置中心阻塞升級

使用 Concrete 時,啟動時異常:

Unable to make field private static final java.lang.reflect.Method jdk.proxy2.$Proxy97.m0 accessible:

module jdk.proxy2 does not "opens jdk.proxy2" to unnamed module @61d47554

原因:

分析下 Concrete 報錯的原因,如下圖,包內 com.wangyin.concrete.spring.ConcreteConfigProcessor#postProcessAfterInitialization(212 行)的實現邏輯

JDK11 升級 JDK17 最全實踐干貨來了

JDK11 升級 JDK17 最全實踐干貨來了

解決方案:

1、在 JVM 啟動參數中設置 --add-opens jdk.proxy2 來開啟私有字段的訪問,但因為動態代理生成的包名是隨機不明確的,所以這種方案不可行。JDK 官方文檔也明確表示不支持訪問動態代理內部的隨機字段。官方說明:https://cr.openjdk.org/~mr/jigsaw/spec/api/java/lang/reflect/Proxy.html

2、代碼修改,只需把 f.setAccessible (true) 移到 Modifier.isStatic (f.getModifiers ()) 的判斷下方即可。原因是方法 Modifier.isStatic (f.getModifiers ()) 本來就要跳過靜態字段,這樣修改直接避免了訪問。推動 concrete 團隊修復問題或更換使用 Ducc 配置中心

6.5、JVM 啟動參數配置

6.5.1、開啟 ZGC

啟動參數中配置:-XX:+UseZGC

移除 - XX:ConcGCThreads,行云部署下 JVM 參數配置需要清除

JDK11 升級 JDK17 最全實踐干貨來了

6.5.2、不同中間件所需啟動參數

升級 JDK17 后,項目啟動時可能會遇到如下兩種類型的異常:

1、cannot access class sun.util.calendar.ZoneInfo (in module java.base) because module java.base does not export sun.util.calendar to unnamed module @0x2611f533

2、Unable to make field final int java.math.BigInteger.signum accessible: module java.base does not "opens java.math" to unnamed module @525f1e4e

異常原因:

自從 JDK9 中引入了模塊化功能后,再到 JDK17,對于包掃描和反射的權限控制更加的嚴格。常見的庫比如(Spring)大量用到包掃描和反射,所以常出現此錯誤。

解決方案:

一個粗暴的解決辦法是將沒開放的 module 強制對外開放,即保持和 Java9 之前的版本一致。

  • --add-exports 導出包,意味著其中的所有公共類型和成員都可以在編譯和運行時訪問。
  • --add-opens 打開包,意味著其中的所有類型和成員(不僅是公共類型)都可以在運行時訪問。

主要區別在于 --add-opens 允許 “深度反射”,即非公共成員的訪問,才可以調用 setAccessible(true)

參考: https://stackoverflow.com/questions/44056405/whats-the-difference-between-add-exports-and-add-opens-in-java-9

SGM 需要加入:

--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

R2M 需要加入:

--add-opens java.base/java.time=ALL-UNNAMED

Ducc 需要加入:

--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

AKS 需要加入:

--add-exports 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

6.6、啟動后的驗證

1. 推薦先升級 JDK11,再到 JDK17,一邊升級一邊進行驗證觀察

2. 觀察日志是否有異常,特別是上面說到的啟動時異常

3. 觀察監控類軟件,比如 SGM、UMP 等監控是否正常

4. 推薦逐步有序切量,并做好常態化壓測,防止影響核心業務

5. 升級完成后,最好能做個全流程的功能測試,防止功能異常

7、總結

1、升級后,除了可以使用新的語法特性,最大的亮點是可以使用亞毫秒級停頓的 GC 性能(至少百倍的 GC 性能提升),所以 強烈建議升級到 JDK17
2、整個升級過程并不復雜,主要涉及到中間件版本的升級和啟動參數的配置

如果還停留在 JDK8,推薦先升級 JDK11,再到 JDK17,具體升級步驟先參考我的上篇文章 “JDK8 升級 JDK11 最全實踐干貨來了”,再參考本章中的升級步驟。

希望以上分享可以給大家帶來實際的幫助,升級過程中如果遇到問題,歡迎大家在評論區回復。

 

作者:京東科技 曲振富
來源:京東云開發者社區 轉載請注明來源

分享到:
標簽:JDK
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定