<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么以及如何升級至 Java 16 或 17

          共 9609字,需瀏覽 20分鐘

           ·

          2021-09-26 07:44


          作者 | Johan Janssen
          譯者 | 平川
          策劃 | Tina

          在 2021 年 4 月 27 日的 InfoQ 直播中,我探討了為什么應(yīng)該考慮升級到 Java 16 或 Java 17(一旦發(fā)布),并就如何完成升級提供了一些實用的建議。

          直播的內(nèi)容基于我個人的 GitHub 庫 JavaUpgrades,其中有文檔和示例介紹了升級到 Java 16 或 Java 17 時常見的難題和異常。其中也有具體的解決方案,你可以用在自己的應(yīng)用程序中。示例要用 Docker 運行,是用 Maven 構(gòu)建的,但是你當(dāng)然也可以設(shè)置自己的 Gradle 構(gòu)建。

          本文以及那次直播都是為了讓用戶可以輕松升級到 Java 16 或 Java 17。大部分常見的升級任務(wù)都討論到了,所以你可以更容易地解決它們,并專注于克服應(yīng)用程序所特有的挑戰(zhàn)。

          為什么要升級?

          Java 的每個新版本,尤其是大版本,都會解決安全漏洞,提升性能,增加新特性。保持 Java 版本最新有助于保持應(yīng)用程序的健康,也有助于組織留住現(xiàn)有的開發(fā)人員,并有可能吸引來新員工,因為開發(fā)人員一般更希望使用比較新的技術(shù)。

          升級有時會被視為一項挑戰(zhàn)

          人們認(rèn)為,升級到 Java 的新版本需要很大的工作量。這是因為代碼庫需要變更,還需要在所有構(gòu)建和運行應(yīng)用程序的服務(wù)器中安裝 Java 的最新版本。幸運的是,有些公司使用了 Docker,團(tuán)隊可以讓它們自己升級這些內(nèi)容。

          許多人將 Java 9 模塊系統(tǒng)(即 Jigsaw)視為一項重大的挑戰(zhàn)。然而,Java 9 并不需要你顯式地使用模塊系統(tǒng)。事實上,大多數(shù)運行在 Java 9 以及更高版本上的應(yīng)用程序并沒有在代碼庫中配置 Java 模塊。

          評估任何升級所需的工作量都是一項挑戰(zhàn)。那取決于多種因素,如依賴項數(shù)量及其現(xiàn)狀。舉例來說,如果你使用的是 Spring Boot,那么升級 Spring Boot 可能已經(jīng)解決大部分升級問題。遺憾的是,由于存在不確定性,大部分開發(fā)人員會將升級工作量評估為許多天、周甚或是月。如此一來,考慮成本、時間或其他優(yōu)先事項,組織或管理層就會推遲升級。我以前見過人們對將 Java 8 應(yīng)用程序升級到 Java 11 的工作量評估從數(shù)周到數(shù)月不等。不過,我曾在幾天內(nèi)完成了一次類似的升級。這一部分是因為我之前的經(jīng)驗,不過,這也得益于我沒有多想就開始了升級過程。周五下午升級 Java 就很理想,看看會發(fā)生什么。我最近將一個 Java 11 應(yīng)用程序升級到了 Java 16,我唯一需要完成的任務(wù)就是升級一個 Lombok 依賴項。

          升級可能很困難,評估所需的時間似乎是不可能的,但通常,實際的升級過程不會花那么多時間。在許多應(yīng)用程序升級中,我都見過同樣的問題。我希望幫助團(tuán)隊快速解決重復(fù)出現(xiàn)的問題,讓他們可以集中精力克服應(yīng)用程序獨有的挑戰(zhàn)。

          Java 的發(fā)版節(jié)奏

          過去,Java 每兩年發(fā)布一個新版本。然而,從 Java 9 發(fā)布之后,新版本發(fā)布變成了每 6 個月一次,長期支持版本(LTS)每 3 年一次。大多數(shù)非長期支持版本都通過小版本升級提供大約 6 個月的支持,直到下一個版本發(fā)布。另一方面,LTS 版本幾年內(nèi)都會收到小版本升級,至少到下個 LTS 版本發(fā)布。實際提供支持的時間可能會更長,這取決于 OpenJDK 的供應(yīng)商(Adoptium、Azul、Corretto 等)。舉例來說,Azul 對于非 LTS 版本提供的支持時間就比較長。

          你可能會問自己,“我應(yīng)該總是升級到最新版本,還是應(yīng)該停留在一個 LTS 版本上?”保證應(yīng)用程序使用的是 LTS 版本意味著你可以利用小版本升級帶來的各種改進(jìn),尤其是與安全相關(guān)的那些。另一方面,在使用最新的非 LTS 版本時,你應(yīng)該每隔 6 個月就升級到一個新的非 LTS 版本,否則就無法利用小版本升級了。

          然而,每 6 個月升一次級是一項不小的挑戰(zhàn),因為在升級應(yīng)用程序之前,你可能不得不等待你所使用的框架完成升級。但是,你應(yīng)該也不會等待太長時間,因為非 LTS 版本的小版本很快就會不再發(fā)布了。在我們公司,我們目前決定停留在 LTS 版本上,因為我們覺得自己沒有時間每 6 個月升級一次,這樣一個時間窗口太小。不過也不絕對,如果團(tuán)隊真得需要,或者一個非 LTS 版本帶來了有趣的 Java 新特性,那么我們也可能改變決定。

          升級到什么版本?

          一般來說,應(yīng)用程序由依賴項和你自己的代碼(打包后在 JDK 上運行)構(gòu)成。如果 JDK 中有什么修改,那么依賴項或 / 和你自己的代碼就需要修改。在大多數(shù)情況下,這是由 JDK 移除了某項特性導(dǎo)致的。如果你的依賴項使用了一項已經(jīng)移除的 JDK 特性,那么請保持耐心,等待該依賴項的新版本發(fā)布。

          多 JDK 版本

          當(dāng)升級應(yīng)用程序時,你可能希望使用 JDK 的不同版本,如最新版本用于實際的升級,老版本用于保持應(yīng)用程序的運行。用于應(yīng)用程序開發(fā)的當(dāng)前 JDK 版本可以通過環(huán)境變量JAVA_HOME指定,也可以借助包管理工具 SDKMAN! 或 JDKMon。

          對于我 GitHub 庫中的示例,我使用 Docker 和不同的 JDK 版本來說明特定的特性如何工作或造成破壞。你可以試一下相關(guān)特性,而不必安裝多個 JDK 版本。遺憾的是,使用 Docker 容器的反饋回路有點長。需要首先構(gòu)建并運行鏡像。所以一般來說,我建議你盡可能從 IDE 內(nèi)升級。但是,在一個干凈的、沒有個性化設(shè)置的 Docker 容器環(huán)境中試驗一些東西或構(gòu)建應(yīng)用程序或許是一個不錯的注意。

          為了說明這一點,我們創(chuàng)建了一個標(biāo)準(zhǔn)的 Dockerfile 文件,其中包含下面的內(nèi)容。該示例使用了 Maven JDK 17 鏡像,并將你的應(yīng)用程序代碼復(fù)制到里面。RUN 命令會運行所有測試,出錯了也不會失敗。

          FROM maven:3.8.1-openjdk-17-slim
          ADD . /yourprojectWORKDIR /yourproject
          RUN mvn test --fail-at-end

          要想構(gòu)建上述鏡像,則運行docker build 命令,并通過-t 指定標(biāo)簽(或名稱),通過. 配置上下文,在本例中是當(dāng)前目錄。

          docker build -t javaupgrade .
          準(zhǔn)備工作

          大多數(shù)開發(fā)人員都是從升級本地環(huán)境開始,然后是構(gòu)建服務(wù)器,最后是各部署環(huán)境。不過,我有時候會直接在構(gòu)建服務(wù)器上使用新版本的 Java 進(jìn)行構(gòu)建,而不是針對這個特定的項目做好所有配置,然后看看會出什么問題。

          一次性從 Java 8 升級到 17 也是可以的。不過,如果你遇到任何問題,可能會很難確定這兩個 Java 版本間的哪個新特性導(dǎo)致了問題。小步升級,比如從 Java 8 升級到 Java 11,定位問題會比較容易。而且,在你搜索問題原因時,加上 Java 版本也是有幫助的。

          我建議在舊版本的 Java 上升級依賴項。那樣你可以專注于讓依賴項可以正常工作,而不必同時升級 Java。遺憾的是,有時候沒法這樣做,因為有些依賴項需要更新的 Java 版本。如果是這樣,你就別無選擇,只能同時升級 Java 和依賴項了。

          Maven 和 Gradle 提供了一些插件,可以顯示依賴項的新版本。mvn versions:display-dependency-updates 命令會調(diào)用 Maven 版本插件。該插件會列出有新版本可用的依賴項:

          [INFO] --- versions-maven-plugin:2.8.1:display-dependency-updates (default-cli) @ mockito_broken ---[INFO] The following dependencies in Dependencies have newer versions:[INFO]   org.junit.jupiter:junit-jupiter .................... 5.7.2 -> 5.8.0-M1[INFO]   org.mockito:mockito-junit-jupiter ................... 3.11.0 -> 3.11.2

          build.gradle 文件中配置好插件后,gradle dependencyUpdates -Drevision=release 命令會調(diào)用 Gradle 版本插件:

          plugins {    id "com.github.ben-manes.versions" version "$version" }

          升級完依賴項后,就可以升級 Java 了。要想把代碼改到在新版本的 Java 上運行,最好是在 IDE 中進(jìn)行,以確保它支持 Java 的最新版本。最后,將構(gòu)建工具升級到最新版本,并配置 Java 版本:

          <plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-compiler-plugin</artifactId>    <version>3.8.1</version>    <configuration>        <release>17</release>    </configuration></plugin>plugins {    java {        toolchain {            languageVersion = JavaLanguageVersion.of(16)        }    }}compile 'org.apache.maven.plugins:maven-compiler-plugin:3.8.1'

          不要忘了把 Maven 和 Gradle 插件升級到最新版本。

          JDK 中移除的特性

          JDK 中總是有些元素可能被移除,包括方法、證書、垃圾收集算法、JVM 選項,甚至是整個工具。不過,在大多數(shù)情況下,這些被移除的部分在刪除之前已經(jīng)被標(biāo)記為“已廢棄”或“將移除”。舉例來說,JAXB 在 Java 9 中已廢棄,但最終移除是在 Java 11 中。如果你已經(jīng)解決了與已廢棄的特性相關(guān)的問題,那么在特性真正被移除時也就不用擔(dān)心了。

          可以參考 Java Version Almanac 和 Foojay Almanac 對 Java 不同版本的比較,看看增加了哪些項,廢棄了哪些項,或者是移除了哪些項。以 Java 增強提案(JEP) 這種形式所做的高級變更可以在 OpenJDK 網(wǎng)站上查看。關(guān)于每個 Java 版本的詳細(xì)信息,可以查閱 Oracle 公布的發(fā)布說明。

          Java 11

          Java 11 移除了多個特性。首先是 JavaFX,它已經(jīng)不在規(guī)范中,也不再捆綁在 OpenJDK 中。不過,有的供應(yīng)商提供的 JDK 構(gòu)建包含的內(nèi)容比規(guī)范里的多。例如,ojdkbuild 和 Liberica JDK 的完整 JDK 都包含了 OpenJFX。此外,你也可以使用 Gluon 提供的 JavaFX 構(gòu)建,或者向應(yīng)用程序添加 OpenJFX 依賴。

          在 JDK 11 之前,有些字體是包含在 JDK 中的。例如,Apache POI 可以把這些字體用于 Word 和 Excel 文檔。然而,在 JDK 11 開始,就不再提供那些字體了。如果操作系統(tǒng)也沒有提供,那么你可能就會遇到一些奇怪的錯誤。解決方案是在操作系統(tǒng)上安裝字體。根據(jù)你在應(yīng)用程序中使用的字體,你可能需要安裝更多的包:

          apt install fontconfigOptional: libfreetype6 fontconfig fonts-dejavu

          Java Mission Control(JMC)是一個監(jiān)控和性能分析應(yīng)用程序,它開銷很小,可以在包括生產(chǎn)環(huán)境在內(nèi)的任何環(huán)境中對應(yīng)用程序做性能分析。如果你沒用過,我強烈建議你用一下。它不再是 JDK 的一部分,但 AdoptOpenJDK 和 Oracle 給它起了一個新名字 JDK Mission Control,并提供了單獨的下載包。Java 11 的最大變化是移除了 Java EE 和 CORBA 模塊,如 4 個 Web 服務(wù) API——JAX-WS、JAXB、JAF 和 Common Annotations——因為已經(jīng)包含在 Java EE 中,所以被認(rèn)為是多余的。在 2017 年發(fā)布后不久,Oracle 就將 Java EE 8 貢獻(xiàn)給了 Eclipse 基金會,旨在使 Java EE 開源??紤]到 Oracle 的品牌策略,有必要將 Java EE 重命名為 Jakarta EE,并將命名空間從 javax 遷移到 jakarta。因此,在使用像 JAXB 這樣的依賴項時,確保自己使用了比較新的 Jakarta EE 工件。例如,JAXB 工件的 Java EE 8 版本名為javax.xml.bind:jaxb-api ,后續(xù)開發(fā)于 2018 年停止。JAXB 的 Jakarta EE 版本在新工件jakarta.xml.bind:jakarta.xml.bind-api 下繼續(xù)開發(fā)。務(wù)必確保應(yīng)用程序中所有的導(dǎo)入都已經(jīng)改為了新命名空間jakarta 。例如,對于 JAXB,將javax.xml.bind.* 改為jakarta.xml.bind.* ,并添加相關(guān)依賴項。下圖中左邊的列是受這項變更影響的模塊。右邊兩列顯示了可以用作依賴項的groupIdartifactId 。請注意,JAXB 和 JAX-WS 都需要兩個依賴項:一個用于 API,一個用于實現(xiàn)。官方?jīng)]有提供 CORBA 的替代方案,但 Glassfish 還是提供了一個可用的工件。

          Java 15

          Java 15 移除了 JavaScript 引擎 Nashorn,不過,你仍然可以通過添加以下依賴項來使用:

          <dependency>    <groupId>org.openjdk.nashorn</groupId>    <artifactId>nashorn-core</artifactId>    <version>15.2</version></dependency>
          Java 16

          在這個版本中,JDK 開發(fā)者封裝了一些 JDK 內(nèi)部構(gòu)件。他們不希望應(yīng)用程序再使用 JDK 的底層 API。這主要影響了 Lombok 這樣的工具。所幸,Lombok 幾個周內(nèi)就發(fā)布了一個新版本,解決了這個問題。

          如果你有任何代碼或依賴項仍然使用 JDK 內(nèi)部構(gòu)件,那么可以嘗試使用 JDK 的高級 API 來解決這個問題。如果不行的話,Maven 還提供了一種變通方法:

          <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration>  <fork>true</fork>  <compilerArgs>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>   <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED</arg>  </compilerArgs> </configuration></plugin>

          我曾嘗試使用 Maven Toolchains 通過在pom.xml 文件中指定 JDK 版本來實現(xiàn) JDK 切換。很遺憾,當(dāng)使用 Lombok 的舊版本在 Java 16 上運行應(yīng)用程序時報錯了:

          [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project broken: Compilation failure -> [Help 1]

          上面就是全部報錯信息。我不知道你怎么看,但在我看來,這沒什么用,所以我提交了這個問題。如果這個問題修復(fù)了,那么使用 Maven Toolchains 切換版本是一種不錯的方法。后來,我直接在 Java 16 上運行代碼,得到了一個更具描述性的錯誤,其中提到了我之前展示的部分變通方案:

          class lombok.javac.apt.LombokProcessor (in unnamed module @0x21bd20ee) cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module
          Java 17

          JDK 維護(hù)人員已經(jīng)就 9 月份要發(fā)布的內(nèi)容 達(dá)成了一致。Applet API 將被廢棄,因為瀏覽器停止支持 Applet 已經(jīng)很長時間了。實驗性的 AOT 和 JIT 編譯器也將被移除。作為實驗性編譯器的替代方案,你可以使用 GraalVM。最大的變化是 JEP-403:強封裝的 JDK 內(nèi)部構(gòu)件。Java 選項--illegal-access 已經(jīng)無效,如果你仍然試圖訪問一個內(nèi)部 API,則會拋出如下異常:

          java.lang.reflect.InaccessibleObjectException:   Unable to make field private final {type} accessible:  module java.base does not "opens {module}" to unnamed module {module}

          大多數(shù)時候,這可以通過升級依賴項或使用高級 API 來解決。如果不行的話,你可以使用--add-opens 參數(shù)來獲得對內(nèi)部 API 的訪問。不過,除非不得已不要這樣做。注意,有些工具在 Java 17 上還無法運行。例如,Gradle 就無法構(gòu)建項目,而 Kotlin 不能使用jvmTarget = "17" 。有些框架,如 Mockito,在 Java 17 上也有些小問題。enum 字段中的方法會導(dǎo)致這個特定的問題。不過,我估計大部分問題都會在 Java 17 發(fā)布之前或發(fā)布之后短期內(nèi)得到解決。對于任何插件或依賴項,你可能會在構(gòu)建應(yīng)用程序時看到這條消息“不支持的類文件主版本 61”。類文件主版本 61 用于 Java 17,60 用于 Java 16。這基本上是說該插件或依賴項不能用于那個 Java 版本。大多數(shù)時候,升級到最新版本就可以解決問題。

          完  工

          在解決了所有挑戰(zhàn)之后,你終于可以在 Java 17 上運行應(yīng)用程序了。經(jīng)過努力,你現(xiàn)在可以使用令人興奮的 Java 新特性了,如記錄和模式匹配。

          小  結(jié)

          升級 Java 是一項挑戰(zhàn),不過這也要看你的 Java 版本和依賴項有多老,你的環(huán)境配置有多復(fù)雜。本文旨在幫助你解決 Java 升級時最常見的挑戰(zhàn)。一般來說,很難評估實際的升級工作要花費多長時間。我覺得,大多數(shù)時候,從 Java 11 升級到 Java 17 要比從 Java 8 升級到 Java 11 簡單。對于大多數(shù)應(yīng)用程序,從一個 LTS 版本升級到下一個 LTS 版本需要幾個小時到幾天的時間。大部分時間都花在了構(gòu)建應(yīng)用程序上。重要的是先開始,然后逐步更改。這樣可以激勵自己、團(tuán)隊和管理層繼續(xù)努力。

          你開始升級應(yīng)用程序了嗎?

          作者簡介:

          Johan Janssen 是 Sanoma Learning 教育部門的一名軟件架構(gòu)師。他特別喜歡分享 Java 相關(guān)的知識。他在 Devoxx、Oracle Code One、Devnexus 等會議上做過演講。他通過參與計劃委員會來協(xié)助大會組織,發(fā)起并組織了 JVMCON。他得過的獎項有 JavaOne Rock Star 和 Oracle Code One Star。他在數(shù)字和印刷媒體上撰寫了各種文章。他是 Chocolatey 各種 Java JDK/JRE 包的維護(hù)者,每月有大約 10 萬次下載。

          原文鏈接:

          https://www.infoq.com/articles/why-how-upgrade-java17/

          瀏覽 60
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  精品国产三级 | 玖玖av| 日韩人妻无码精品综合区 | 日韩 欧美 国产高清91 | 黄片视频在线观看 |