保姆級(jí)升級(jí) java17 指南,建議收藏

一、前言
Java 17,一個(gè)長期支持 (LTS) 版本已經(jīng)發(fā)布半個(gè)多月。不幸的是,許多應(yīng)用程序仍在舊版本的 Java 上運(yùn)行,例如以前的 LTS 版本:Java 8 和 Java 11。本文解釋了你應(yīng)該升級(jí)應(yīng)用程序的原因,并幫助你實(shí)際升級(jí)到 Java 17。
但首先,許多人都可能會(huì)問:“為什么要升級(jí)?”
java9 緊湊字符串(更加節(jié)省內(nèi)存) java11 httpclient java12 switch 表達(dá)式(簡(jiǎn)化代碼) java13 多行文本 java14 record,匹配模式(簡(jiǎn)化代碼) 等等...
隨著 Java 版本迭代,GC 得到大量優(yōu)化,相對(duì)于老版本更快并且節(jié)省內(nèi)存。僅僅靠升級(jí) Java 版本就可以為我們帶來眾多收益。
二、在 Java 升級(jí)期間需要更改什么?
你的應(yīng)用程序包含你和你的團(tuán)隊(duì)編寫的代碼,并且可能還包含依賴項(xiàng)。如果從 JDK 中刪除了某些內(nèi)容,則可能會(huì)破壞代碼、依賴項(xiàng)或兩者。通常有助于確保這些依賴項(xiàng)是最新的,以解決這些問題。有時(shí),你可能需要等到框架發(fā)布與最新 Java 版本兼容的新版本,然后才能開始升級(jí)過程。這意味著作為升級(jí)前評(píng)估過程的一部分,你對(duì)你使用的依賴項(xiàng)需要有很好的了解。
大多數(shù)功能不會(huì)一次性從 JDK 中全部刪除。首先,功能被標(biāo)記為棄用。例如,用于 XML 綁定的 Java 架構(gòu) (JAXB) 在 Java 9 中被標(biāo)記為棄用,然后在 Java 11 中才被刪除。如果你一直在更新,那么你會(huì)知道棄用,并且你可以在功能被刪除之前解決這些問題。但是,如果你直接從 Java 8 跳到 Java 17,那么可能會(huì)踩到很多坑。
要查看 API 更改,例如,查看特定 Java 版本中哪些方法被刪除或添加到 String API 中,請(qǐng)查看 Marc Hoffmann 和 Cay Horstmann 撰寫的 The Java Version Almanac。
三、多版本 JAR 功能
如果你的基礎(chǔ)組件任然被使用在舊的 JDK并且在他們的站點(diǎn)上升級(jí)不受你的控制怎么辦?Java 9 和 JEP 238 中引入的多版本 JAR 功能可能很有用,因?yàn)樗试S你將多個(gè) Java 版本(包括早于 Java 9 的版本)的代碼打包在一個(gè) JAR 文件中。
例如:創(chuàng)建一個(gè) Application 類(清單 1)和一個(gè) Student 類(清單 2)并將它們放在文件夾 src/main/java/com/example 中,Student 類在 Java 8 上運(yùn)行。
清單 1. Application class
public?class?Application?{
???public?static?void?main(String[]?args)?{
???????Student?student?=?new?Student("James?");
???????System.out.println("Implementation?"?+?student.implementation());
???????System.out.println("Student?name?James?contains?a?blank:?"?+?student.isBlankName());
???}
}
清單 2. Student class for Java 8
public?class?Student?{
???final?private?String?firstName;
???public?Student(String?firstName)?{
???????this.firstName?=?firstName;
???}
???boolean?isBlankName()?{
???????return?firstName?==?null?||?firstName.trim().isEmpty();
???}
???static?String?implementation()?{?return?"class";?}
}
接下來,創(chuàng)建一個(gè) Student record(清單 3),它不僅使用了 record(Java 14 中引入)而且還使用了 ?String.isBlank() 方法(Java 11 中引入),并將其放在 src/main/java17/com/example 文件夾。
清單 3. 使用新語法的 Student record
public?record?Student(String?firstName)?{
???boolean?isBlankName()?{
???????return?firstName.isBlank();
???}
???static?String?implementation()?{?return?"record";?}
}
根據(jù)你使用的構(gòu)建工具,需要一些配置。Maven 示例可以在我的 GitHub repository 中找到。該示例基于 Java 17 構(gòu)建并創(chuàng)建 JAR 文件。在 JDK 17 或更高版本上執(zhí)行 JAR 文件時(shí),將使用學(xué)生記錄。在舊版本上執(zhí)行 JAR 文件時(shí),將使用 Student 類。
當(dāng)然你也可以參考 https://github.com/xkcoding/simple-http,筆者給它 pr 了 java11 下的 HttpClient 支持,該工具使用 Java8 編譯。
此功能非常有用,例如,如果新 API 提供更好的性能,因?yàn)槟憧梢詾閾碛凶钚?Java 版本的客戶使用這些 API。相同的 JAR 文件可用于使用較舊 JDK 的客戶,而不會(huì)提高性能。
請(qǐng)注意,所有實(shí)現(xiàn)(在本例中為 Student)都應(yīng)具有相同的公共 API 以防止運(yùn)行時(shí)問題。不幸的是,構(gòu)建工具不會(huì)驗(yàn)證公共 API,但一些 IDE 會(huì)驗(yàn)證。另外,在 JDK 17 中,你可以使用 jar –validate 命令來驗(yàn)證 JAR 文件。
需要注意的是某些版本的 JDK 中存在預(yù)覽功能。一些更大的特性首先作為預(yù)覽發(fā)布,并且可能會(huì)在下一個(gè) JDK 之一中產(chǎn)生最終特性。這些預(yù)覽功能同時(shí)存在于 Java 的 LTS 和非 LTS 版本中。這些功能使用 enable-preview標(biāo)志啟用,默認(rèn)情況下關(guān)閉。如果你在生產(chǎn)代碼中使用這些預(yù)覽功能,請(qǐng)注意它們可能會(huì)在 JDK 版本之間發(fā)生變化,這可能會(huì)導(dǎo)致需要將代碼進(jìn)行一些調(diào)試或重構(gòu)。
四、有關(guān) Java 棄用和刪除的功能
在升級(jí) JDK 之前,請(qǐng)確保你的 IDE、構(gòu)建工具和依賴項(xiàng)是最新的。Maven Versions Plugin 和 Gradle Versions Plugin 顯示你擁有哪些依賴項(xiàng)并列出最新的可用版本。
請(qǐng)注意,這些工具僅顯示你使用的依賴的新版本——但有時(shí)依賴的名稱會(huì)發(fā)生變化、分叉或代碼移動(dòng)。例如:JAXB 最初是通過 javax.xml.bind:jaxb-api 提供的,但在它過渡到 Eclipse Foundation 后更改為 ?jakarta.xml.bind:jakarta.xml.bind-api。要查找此類更改,你可以使用 Jonathan Lermitage 的 Old GroupIds Alerter plugin for Maven 或他的 plugin for Gradle。
JavaFX. 從 Java 11 開始,不再包含 JavaFX 作為規(guī)范的一部分,并且大多數(shù) JDK 版本已將其刪除。你可以使用來自 Gluon 的單獨(dú)構(gòu)建的 JavaFX 或?qū)?OpenJFX 依賴項(xiàng)添加到你的項(xiàng)目。
Fonts. 曾幾何時(shí),JDK 包含一些字體,但從 Java 11 開始,它們被刪除了。例如:如果你使用 Apache POI(Microsoft Office 兼容文檔的 Java API),你將需要字體。操作系統(tǒng)需要提供字體,因?yàn)樗鼈儾辉俅嬖谟?JDK 中。但是,在 Alpine Linux 等操作系統(tǒng)上,必須使用 apt install fontconfig 命令手動(dòng)安裝字體。根據(jù)你使用的字體,可能需要額外的包。
Java Mission Control. 這是一個(gè)非常有用的工具,用于監(jiān)視和分析你的應(yīng)用程序。強(qiáng)烈建議你了解一下。Java Mission Control 曾經(jīng)包含在 JDK 中,但現(xiàn)在改了名并且需要單獨(dú)下載:JDK Mission Control。
Java EE. JDK 11 中最大的變化是刪除了 Java EE 模塊。許多應(yīng)用程序都依賴 Java EE 模塊,例如:前面提到的 JAXB。由于這些模塊不再存在于 JDK 中,因此你需要添加相關(guān)的依賴項(xiàng)。表格 1 列出了各種模塊及其依賴項(xiàng)。請(qǐng)注意,JAXB 和 JAX-WS 都需要兩個(gè)依賴項(xiàng):一個(gè)用于 API,另一個(gè)用于實(shí)現(xiàn)。另一個(gè)變化是命名約定,因?yàn)?Java EE 由 Eclipse 基金會(huì)以 Jakarta EE 的名義進(jìn)行維護(hù)。你的包導(dǎo)入可能需要調(diào)整,較新版本的 Jakarta EE 使用 ?jakarta.xml.bind.* 而不是 javax.xml.bind.*。
表格 1. Java EE 模塊和當(dāng)前的替代品
CORBA. Java 的 CORBA 模塊沒有官方替代品,該模塊在 Java 11 中被刪除。但是 Oracle GlassFish Server 包含了 CORBA 的實(shí)現(xiàn)。
Nashorn. Java 15 刪除了 Nashorn JavaScript 引擎。如果仍想使用它,你可以添加 nashorn-core 依賴。
????org.openjdk.nashorn
????nashorn-core
????15.3
Experimental compilers. Java 17 刪除了對(duì) GraalVM 的實(shí)驗(yàn)性提前 (AOT) 和即時(shí) (JIT) 編譯器的支持,詳見 JEP 410。
五、尋找不受支持的文件
你可能會(huì)遇到 Unsupported class file major version 61 這樣的錯(cuò)誤。我已經(jīng)在 JaCoCo 代碼覆蓋庫和各種其他 Maven 插件中看到了它。消息中版本 61 指的是 Java 17。因此,在這種情況下,這意味著你使用的框架或工具的版本不支持 Java 17。因此,你應(yīng)該將框架或工具升級(jí)到 新版本。
六、JDK 內(nèi)部 API
Java 16 和 Java 17 封裝了 JDK 內(nèi)部 API,這會(huì)影響 Lombok 等各種框架。你可能會(huì)看到諸如 module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module,這意味著你的應(yīng)用程序無法再訪問 JDK 的這些內(nèi)部 API。
通常,我建議升級(jí)所有使用這些內(nèi)部結(jié)構(gòu)的依賴項(xiàng),并確保你自己的代碼不再使用 JDK 的內(nèi)部 API。
如果這是不可能的,有一個(gè)變通方法仍然使你的應(yīng)用程序能夠訪問內(nèi)部。例如,如果你需要訪問 comp 模塊,請(qǐng)使用以下命令:
--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
但是,這只是解決問題的最后手段,最好還是停止使用這些內(nèi)部 API,因?yàn)槟阏诶@過 Java 團(tuán)隊(duì)添加的重要保護(hù)措施。
關(guān)于此問題更多詳細(xì)信息可查看 Java 16 的 JEP 396 和 Java 17 的 JEP 403。
七、結(jié)論
升級(jí)依賴項(xiàng)和為 JDK 已經(jīng)刪除的功能找到替代方案就可以避免大部問題。我推薦一種結(jié)構(gòu)化的方法來逐步升級(jí):首先,確保代碼可以編譯,然后運(yùn)行測(cè)試,然后運(yùn)行應(yīng)用程序。
如果你可以告訴自己、你的團(tuán)隊(duì)和你的公司,你可以在 JDK 17 上編譯和測(cè)試所有內(nèi)容,而不必告訴他們幾乎已經(jīng)完成,或者更糟糕的是,它只完成了 80%,那么遷移過程就會(huì)好得多。
筆者開源的微服務(wù)組件 mica 已經(jīng)適配 java17,mybatis-plus 新版也已經(jīng)支持。目前筆者已經(jīng)有一部分服務(wù)升級(jí)到 Java17,很絲滑,如果你有升級(jí) Java 的想法,不妨直接升級(jí)到 Java17。
關(guān)注 JAVA架構(gòu)日記,學(xué)習(xí)技術(shù)不迷路!
