JDK11升級JDK17最全實踐乾貨來了
來源:京東雲開發者
2021年9月14日,Oracle釋出了可以長期支援的JDK17版本,那麼從JDK11到JDK17,到底帶來了哪些特性呢?亞毫秒級的ZGC效果到底怎麼樣呢?值得我們升級嗎?而且升級過程會遇到哪些問題呢?帶著這些問題,本篇文章將帶來完整的JDK11升級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的用例基準測試表明:https://www.optaplanner.org/blog/2021/09/15/HowMuchFasterIsJava17.html)
最大的亮點是帶來了穩定版的ZGC垃圾回收器,達到亞毫秒級停頓。
3)新語法和特性
Switch表示式簡化、Text Blocks文字塊、instanceof 的模式匹配升級和NullPointerException提示資訊改進等
4)支援最新的技術和框架
Spring framework6 和Spring Boot3 都預設使用 Java 17作為最低版本
先給出結論:
JDK17相對於JDK8和JDK11,所有垃圾回收器的效能都有很明顯的提升,特別是穩定版的ZGC垃圾回收器
不論任何機器配置下,都推薦使用ZGC,ZGC的停頓時間達到亞毫秒級,吞吐量也比較高
我在JDOS平臺上選擇了不同配置的機器(2C4G、4C8G、8C16G),並分別使用JDK8、JDK11和JDK17進行部署和壓測。
整個壓測過程限時60分鐘,用180個虛擬使用者併發請求一個介面,每次介面請求都建立512Kb的資料。最終產出不同GC回收器的各項指標資料,來分析GC的效能提升效果。
以下是壓測的效能情況:
2021年9月,Oracle宣佈JDK17可以免費商用,直到下一個 LTS 版本之後繼續提供整整一年,同時Oracle 將繼續按照自 Java 9 以來的相同版本和時間表提供GPL下的Oracle OpenJDK 版本。
2023年9月,OracleJDK釋出了新的LTS版本 JDK21,這就意味著從2024年9月開始,在生產環境使用 OracleJDK17 將需要付費。
參考:
OracleJDK和OpenJDK這兩個之間沒有真正的技術差別,因為針對Oracle JDK構建過程是基於OpenJDK的。自從JDK11開始,OracleJDK和OpenJDK在功能上基本相同,所以推薦使用 OpenJDK17 或其他開源的JDK版本,這些開源版本都是基於OpenJDK構建並提供長期支援的,比如:AdoptOpenJDK、RedHatOpenJDK。
官方參考:https://blogs.oracle.com/java/post/oracle-jdk-releases-for-java-11-and-later
5.1、JVM改進
ZGC垃圾回收器從實驗性功能更改為正式產品功能,從JDK11引入以來,經過持續的迭代升級,目前已經足夠穩定。需要手動開啟,開啟方式:-XX:+UseZGC
G1垃圾回收器仍然作為預設垃圾回收器,進行改進升級,主要包括可中止的混合收集集合、NUMA 可識別記憶體分配等
JDK14開始刪除 CMS 垃圾回收器
JDK14開始棄用 ParallelScavenge 和 SerialOld GC 的組合使用
JDK15禁用偏向鎖,預設禁用:-XX:+UseBiasedLocking
NullPointerException 提示資訊改進
JDK14以前的出現NullPointerException時,只能定位到所在異常行,無法定位具體是哪個變數。改進後的NullPointerException,可以清晰描述具體變數,提升了空指標異常的可讀性。
5.2、新語法特性
5.2.1、Switch表示式簡化
switch表示式帶來了簡化式的編碼方式,提供了新的分支切換方式,即 -> 符號,右則表示式方法體在執行完分支方法之後,自動結束 switch 分支,同時 -> 右則方法塊中可以是表示式、程式碼塊或者是手動丟擲的異常
參考:
傳統寫法
新寫法
5.2.2、Text Blocks文字塊
參考:
透過編寫 """,來減少跳脫字元和換行符,達到簡化程式碼和提高程式碼可讀性的目的
5.2.3、Record型別
參考:
record 是 JDK 14 引入的關鍵字,用於宣告不可變的資料類。它適用於儲存純粹的值型別資料,如介面傳輸資料、座標點和只讀的日誌記錄。與 lombok 相比,record 簡化了定義純粹資料型別的過程。由於 record 類是不可變的,成員變數只能設定一次且無法更改,無需提供顯式的 setter() 方法。
1、定義Point類,使用關鍵字record,未定義get/set
2、檢視編譯後的位元組碼檔案
3、使用Point類
5.2.4、instanceof 的模式匹配升級
instanceof型別判斷再也不需要強制轉換
6.1、JDK選擇
6.2、pom編譯配置升級
<properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target></properties>
6.3、SpringBoot升級
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.15</version></parent>
<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.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>
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 不相容問題
**/
public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
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);
}
"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);
}
}
};
}
6.4.3、AKS升級(針對直接從JDK8升級的情況)
<!-- 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配置中心阻塞升級
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
在JVM啟動引數中設定--add-opens jdk.proxy2來開啟私有欄位的訪問,但因為動態代理生成的包名是隨機不明確的,所以這種方案不可行。JDK官方文件也明確表示不支援訪問動態代理內部的隨機欄位。官方說明:~mr/jigsaw/spec/api/java/lang/reflect/Proxy.html 程式碼修改,只需把 f.setAccessible(true) 移到 Modifier.isStatic(f.getModifiers()) 的判斷下方即可。原因是方法 Modifier.isStatic(f.getModifiers()) 本來就要跳過靜態欄位,這樣修改直接避免了訪問。推動concrete團隊修復問題
6.5、JVM啟動引數配置
6.5.1、開啟ZGC
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 Unable to make field final int java.math.BigInteger.signum accessible: module java.base does not "opens java.math" to unnamed module @525f1e4e
--add-exports匯出包,意味著其中的所有公共型別和成員都可以在編譯和執行時訪問。 --add-opens開啟包,意味著其中的所有型別和成員(不僅是公共型別)都可以在執行時訪問。
--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/java.time=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-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、啟動後的驗證
推薦先升級JDK11,再到JDK17,一邊升級一邊進行驗證觀察 觀察日誌是否有異常,特別是上面說到的啟動時異常 觀察監控類軟體,比如SGM、UMP等監控是否正常 推薦逐步有序切量,並做好常態化壓測,防止影響核心業務 升級完成後,最好能做個全流程的功能測試,防止功能異常
升級後,除了可以使用新的語法特性,最大的亮點是可以使用亞毫秒級停頓的GC效能(至少百倍的GC效能提升),所以 強烈建議升級到JDK17 整個升級過程並不複雜,主要涉及到中介軟體版本的升級和啟動引數的配置
-end-
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024924/viewspace-2995592/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 讓Elasticsearch飛起來!——效能優化實踐乾貨Elasticsearch優化
- 讓 Elasticsearch 飛起來!——效能優化實踐乾貨Elasticsearch優化
- 從JDK8升級到JDK17JDK
- 你們要的乾貨來了——實戰 Spring BootSpring Boot
- 【乾貨】DDM實踐:資料庫秒級平滑擴容方案資料庫
- 前端乾貨之JS最佳實踐前端JS
- GopherChina 2021 定了,乾貨滿滿的來了Go
- jdk8 升級 jdk17 docker 部署失敗JDKDocker
- 【乾貨】分庫分表最佳實踐
- 升級Webpack5實踐Web
- 【乾貨】Apache DolphinScheduler2.0升級3.0版本方案Apache
- 乾貨 | 京東雲部署Wordpress最佳實踐
- 乾貨收藏!Calico的BGP RouteReflector策略實踐
- 最佳實踐 | 原始碼升級gcc原始碼GC
- 乾貨來了:Chrome常用快捷鍵整理彙總Chrome
- 虹科乾貨 | 零售業數智升級不掉隊,get資料,get未來!
- JupyterLab 3來了請立即升級 - kdnuggets
- 奈學乾貨分享:分散式CAP實踐分析分散式
- 乾貨:PHP與大資料開發實踐PHP大資料
- Kubernetes 叢集無損升級實踐
- JDK的第三個LTS版本JDK17來了JDK
- 融雲IM乾貨丨開源 IMKit 修改後如何升級版本
- C語言實現多級濾波—乾貨C語言
- 史上最全遊戲策劃入門乾貨(一)遊戲
- 史上最全遊戲策劃入門乾貨(三)遊戲
- 史上最全遊戲策劃入門乾貨(二)遊戲
- 史上最全遊戲策劃入門乾貨(四)遊戲
- 乾貨 | 京東雲賬號安全管理最佳實踐
- 乾貨:如何監控伺服器效能實踐篇伺服器
- HDFS3.2升級在滴滴的實踐S3
- AWS RDS強制升級的應對之道——版本升級的最佳實踐
- 加油吧,原力計劃升級版來了!
- 頂級實用乾貨——談談Java中的volatileJava
- 技術乾貨|如何實現分鐘級故障管理
- 用git管理你的專案吧(最全的乾貨)Git
- 最全的Logback快速實踐
- 乾貨|EasyMR 基於 Kubernetes 應用的監控實踐
- 乾貨 | 京東技術中臺的Flutter實踐之路Flutter