1. 程式人生 > >【Java】JDK9 內部探索——版本架構,多版本 jar 包及其他

【Java】JDK9 內部探索——版本架構,多版本 jar 包及其他

JShell

因為已經有很多人在談論 Jigsaw,因此在第一部分我們先跳過不去講它。在這一部分我們將會照本宣科地拿 JShell 做些事情, 這是 Java 的一個全新的 REPL (說到它能做的事情,例如你在一個地方敲入了 Java 程式碼,有了它就可以馬上把程式碼的執行結果計算出來)。如果你還並不(特別地)瞭解這個東西但又感覺有點興趣的話,可以看看 Robert Field 在 去年的 Devoxx Belgium 上提供的 這份不錯的介紹 。

新的版本字串

讓我們先來個簡單的入門介紹: 版本名稱。

我嘗試過去理解 Java的版本命名模式 ,直到這樣做的時候才覺得值得去深究一番。它是從 1.0 和 1.1 版本的 JDK 開始的 – 這倆版本還算是那麼回事兒,但這倆版本以後就越來越不那麼像話了。版本 1.2 到 1.5 對商標進行了重新命名,如 Java 2 這樣的,改變比較明顯(還記得J2SE 嗎 ? 其實指的就是 2 這個版本) 。到了  JDK 1.5 就很明顯可以看出上述的命令模式沒有真正起作用,因此 Sun就開始將它叫做 Java 5 了。圍繞 Java 6,整個自 Java 2 開始的命名創意被悄無聲息的埋沒了,不過這樣反而更讓人明白——我們簡單的叫它“Java X”就可以了。 (你是否知道 Java 版本,包含 Java 7 其實都有一個像  Tiger和Mustang這樣 很酷的工程名字?)

JVM 所報告的版本字串並沒有做出修改——它們總會是 1.x.... 這樣的形式,不過現在有了 JEP 223 , 版本字串和命令模式做了對齊。如果檢查相關的系統屬性(見這裡的 demo ), 輸出會是下面這樣的內容:

java.version: 9-ea
java.runtime.version: 9-ea+138-jigsaw-nightly-h5561-20161003
java.vm.version: 9-ea+138-jigsaw-nightly-h5561-20161003
java.specification.version: 9
java.vm.specification.version: 9

這並非過分顯示的資訊,因為它是跑在一個早期可訪問的構建本上的。在將來 java.version 會報告像 9.1.2 這樣的字串, 所遵循的是 $MAJOR.$MINOR.$SECURITY 模式:

  • $MAJOR 所標識的是 Oracle 計劃每兩到三年釋出的主版本號。

    Version version = Runtime.version();
    System.out.println("Reported by runtime: " + version);
    switch (version.major()) {
        case 9:
            System.out.println("Modularity!");
            break;
        case 10:
            System.out.println("Value Types!");
            break;

  • $MINOR 所標識的是針對Bug修復以及一些其它需要定期跟進的更小一點的版本號——當主版本號釋出時,這個標識就會被重置為零。

  • $SECURITY 則相當有意思 – 這個標識在每次釋出中“含有包括為提升安全性而進行的重要修復”時就會要用到,並且在 $MINOR 變大的時候它並不會被 重置。

現在我們已經沒必要對這些字串進行轉換了,因為有了 Version , 這是一個能為我們做這些事情的小類,很不錯。

GNU 風格的命令列選項

當涉及到命令選項的語法時,Java 的各種工具就有點太過於形式各異了:

  • 有些會在 長版本選項前面 使用一個短橫線(-classpath),其它則會使用兩個(--gzip)

  • 有些用短橫線分隔單詞(--no-gzip),其它則沒有這樣做(-classpath)

  • 有些是單個字母形式的(-d), 其它則是兩個字母形式的(-cp, 真不知道那樣搞是為了啥?!)

  • 有些用等號賦值(-D<name>=<value>), 其它則需要一個空格(我可不會這樣做…)

相比之下,在 Linux 以及其它基於 GNU 的系統上幾乎所有工具的選項都使用的是相同的語法:

  • 長版本選項前面都是使用兩個短橫線

  • 單詞都用短橫線分隔

  • 選項縮寫都會使用一個短橫線並且只會包含一個字母

在一次不顧一切的魯莽行動中,Java 9 快刀斬亂麻,修改了所有的命令列選項以匹配上述這些規則!好吧,這個只是跟你開個玩笑… 不過 JEP 293 已經確定了一個準則來反映和適配這些規則,並且新的選項預期也會遵循這個準則。老的選項可能會在某些時候向這種更加乾淨的語法遷移,但那並不是 Java 9 開發工作的一部分。JEP 包含了許多詳細內容以及示例 – 值得一讀。

擴充套件和更新

有很多 JEP(Java Expression Parser,Java表示式分析器)會隨 Java 9 釋出,它們會帶來對已存在功能的提高擴充套件和更新。下面介紹它們,以主題為序,有些總結,有些細節。

Unicode

Java 自身可以用 UTF-16 (你的程式碼裡可以用 emoji)[譯者注:emoji 是 Unicode 的表情符號]來寫程式碼,屬性檔案則必須使用 ISO-8859-1。來看看,如果有一個像這樣的 config.properties 檔案:

money = € / \u20AC

在 Java 8 中訪問這個檔案:

money = â▯¬ / €

JEP 226 終結了那個時代,不再需要進行  Unicode 轉義。Java 9 中同樣的程式碼訪問這個檔案會得到我們期望的結果:

money = € / €

(有一個 完整示例 ,不過我們的程式碼高亮不太好用。)

值得注意的是,我們有很多種方法用於訪問屬性檔案,但是隻有通過 PropertyResourceBundle 訪問的這種方法被更新了。 JavaDoc 中的 API 文件說明了如何精確的檢測編碼以及如何對其進行配置。預設配置是明智的,雖然它只是讓 API 在一般情況下  “可以工作”:

try (InputStream propertyFile = new FileInputStream("config.properties")) {
    PropertyResourceBundle properties = new PropertyResourceBundle(propertyFile);
    properties.getKeys().asIterator().forEachRemaining(key -> {
        String value = properties.getString(key);
        System.out.println(key + " = " + value);
    });} catch (IOException e) {
    e.printStackTrace();}

在 示例 中你可以找到使用了 Properties API 的程式碼。如果你想在 Java 8 中執行它來進行比較,你會發現 Java 9 的 API 中有一個漂亮的小修改。這個小修改是為仍然在使用古老的 Enumeration 的可憐開發者而做。

在其它 Unicode 相關的新聞裡,Java 9 支付了 Unicode 8.0 。耶!

圖形影象

影象 I/O 框架(在 javax . imageio 包中) 現在支援TIFF 了。Java 高階影象處理(Java Advanced Imaging,JAI)專案 實現了對 TIFF 的讀寫。它已經完成標準化並移到javax.imageio.plugins.tiff 包中。

視網膜 HiDPI 螢幕為桌面 UI 帶來特有的挑戰。Java已經在 Mac 上處理好了這個問題,現在緊跟著開始適配 Linux 和 Windows。“視窗和 GUI 元件會基於平臺推薦而擁有一個合適的大小,在任何 HiDPI 設定下,預設的綻放都應該讓文字應保持高清,圖示和影象在合適的顯示密度上應該光滑並儘可能地展現細節。”  

Linux 上 Java 桌面的三劍客(AWT、Swing 和 JavaFX)現在可以使用 GTK 3 。一開始JVM 會預設使用 GTK 2,只能通過 jdk.gtk.version 來配置使用  GTK 3。“互動性”需要 GTK 3,這個需求很早就能被探測到”。

JavaFX 使用過時的 GStreamer 版本,目前更新到了 1.4.4。新版本會提供 JavaFX 在播放媒體時的穩定性和效能。

HarfBuzz 是新的  OpenType 佈局引擎,取代了已被停用的  ICU 。

安全性

SHA-3雜湊演算法已經實現了 SHA3-224、SHA3-256、SHA3-384 和 SHA3-512。可以通過  MessageDigestAPI 使用它們。

在使用 SecureRandom(在任何 Java 版本中)時,你可以獲取作業系統的原生實現,或者 純 Java 實現的版本 。後者是“舊的基於 SHA-1 的 RNG 實現,它的健壯性不如被認可的   DRBG  [Deterministic Random Bit Generator] 機制。 ”既然是舊的,特別是嵌入式系統,它依賴於 Java 變化,它的安全性隨  NIST 800-90Ar1 所描述的 DRBG 機制得到了提升。SecureRandom API 已經被改進,可以傳遞引數以使用 DRBG 和將來的演算法。 

Instantiation instantiation = DrbgParameters.instantiation(128, RESEED_ONLY, null);
SecureRandom random = SecureRandom.getInstance("DRBG", instantiation);

byte[] bytes = new byte[20];
random.nextBytes(bytes);

新的 Java 虛擬機器特性

機器可以代替我們工作——我想知道是否有一天會實現?它會獲得一些新的特性,並被人們所喜愛,但一旦它在我們生活中出現,我們可能又要花上好幾年去適應它。如果不能實現的話,我現在先介紹另一個“新機器”—— insect  機器。

包含多個發行版的 JAR 包

可能你有時候會想為不同的 Java 執行版本寫程式碼——在 Java 8 上做 一些事情 ,在 Java 9 上做 另外一些事情 。到現在為止,這處理起來都很棘手,不過 Java 9 解決了這個問題最重要的部分。現在所有不同的 Java 平臺都能建立,也能認識包多個發行版的 JAR 包,它會包含同一型別的不同版本,這些版本對應不同的 Java 版本。

來看個示例:

  1. 先建立三個類:Main、VersionDependent用於 Java8,還有 VersionDependentfor 用於 Java 9。後續的程式碼提供一個用於列印的結果,內容是 “Java X version”,其中 X 是8 或 9。

  2. 然後編譯 Main 和 VersionDependent(用於 Java 8 的),結果放在目錄 out-mr/java8 上;編譯VersionDependent(Java 9 的版本) 放在 out-mr/java9 上。

  3. 現在開始有趣了,來看看怎麼打包。下面的命令會建立一個 mr.jar,包含兩個 VersionDependent.class (分別來源於 out-mr/java-x 目錄)。因為結構明確,所以 java 能選擇正確的類:

    jar9 --create --file out-mr/mr.jar -C out-mr/java-8 . \    --release 9 -C out-mr/java-9 .
  4. 確實,使用 Java 8 執行 java -cp out-mr/mr.jar ...Main 會輸出 “Java 8 version” 而 使用 Java 9 執行會輸出 “Java 9 version”。

JAR 內部結構看起來像這樣:

└ org
    └ codefx ... (moar folders)
        ├ Main.class
        └ VersionDependent.class
└ META-INF
    └ versions
        └ 9
            └ org
                └ codefx ... (moar folders)
                    └ VersionDependent.class

Java 8 或更早的版本會在直接使用 org 下面的類,但新版本會使在 META-INFO/versions 子目錄中去找合適的內容來代替預設的。乾淨利落。

統一的日誌

除錯 JVM,可能要找到應用崩潰或者效能低下的原因,這已經夠複雜了。而不同的日誌系統有著完全不同的選項,這並不能讓事件變得簡單。幸好有即將通過的 JEP 158 和271 ,它帶來了新的命令列引數 -Xlog(現在不應該是 --log?)可以用來定義極盡詳細的日誌級別。這裡有一些可用的設定:

  • 每個訊息可以有大量的標籤,這依賴於建立和使用它的子系統,如 aregc、模組、oros等。可以選中單獨的標籤並對其應用其它設定。

  • 當然訊息有等級 (error,warning,info,debug,trace,develop) 而且可以按等級進行過濾。

  • 可以為日誌檔案轉換設定輸出到 stdout、stderr 或者檔案。

  • 然後還有 裝飾 – 附加在訊息上的有用資訊(pid、uptime、…、技術標籤和等級都是裝飾)。它們都可以被輸出。

這一些都可以由單獨的 -Xlog 選項完成。讓我們從簡單的記錄幾個標籤開始:

java9 -cp out-mr/mr.jar -Xlog:os,modules,gc ...Main

[0.002s][info][os] SafePoint Polling address: 0x00007feea4c96000
[0.002s][info][os] Memory Serialize Page address: 0x00007feea4c94000
[0.002s][info][os] HotSpot is running with glibc 2.22, NPTL 2.22
[0.009s][info][gc] Using G1
Java 9 version

咦,難道沒有模組資訊?讓我們把那個標籤改為 debug(如果沒有指定等級,預設是 info):

java9 -cp out-mr/mr.jar -Xlog:os,modules=debug,gc org.codefx.demo.java9.internal.multi_release.Main

[0.002s][info][os] SafePoint Polling address: 0x00007f3054a22000
[0.002s][info][os] Memory Serialize Page address: 0x00007f3054a20000
[0.002s][info][os] HotSpot is running with glibc 2.22, NPTL 2.22
[0.009s][info][gc] Using G1
[0.059s][debug][modules] set_bootloader_unnamed_module(): recording unnamed module for boot loader
[0.063s][debug][modules] define_javabase_module(): Definition of module: java.base, version: 9-ea, location: jrt:/java.base, package #: 159
[... snip ... many, many more module messages ... ]

太多了,不過我們可以看到這樣:

[0.079s][info][modules,startuptime] Phase2 initialization, 0.0366552 secs

嘿,這是 info!為什麼之前它沒有顯示出來?!Hey, that’sinfo! Why did it not show up before?! 令人驚異的是它有兩個標籤,在命令中只匹配其中 一個 標籤是不夠的——必須匹配 所有 標籤。我們可以通過 modules+startuptime 或者使用萬用字元來擴充套件匹配:

java9 -cp out-mr/mr.jar -Xlog:os,modules*,gc* ...Main

[0.002s][info][os] SafePoint Polling address: 0x00007f9c7f307000
[0.002s][info][os] Memory Serialize Page address: 0x00007f9c7f305000
[0.003s][info][os] HotSpot is running with glibc 2.22, NPTL 2.22
[0.007s][info][gc,heap] Heap region size: 1M
[0.009s][info][gc     ] Using G1
[0.009s][info][gc,heap,coops] Heap address: 0x00000006c6200000, size: 3998 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
[0.077s][info][modules,startuptime] Phase2 initialization, 0.0367418 secs
Java 9 version
[0.090s][info][gc,heap,exit       ] Heap
[0.090s][info][gc,heap,exit       ]  garbage-first heap   total 256000K, used 2048K [0x00000006c6200000, 0x00000006c63007d0, 0x00000007c0000000)
[0.090s][info][gc,heap,exit       ]   region size 1024K, 3 young (3072K), 0 survivors (0K)
[0.090s][info][gc,heap,exit       ]  Metaspace       used 4225K, capacity 4532K, committed 4864K, reserved 1056768K
[0.090s][info][gc,heap,exit       ]   class space    used 414K, capacity 428K, committed 512K, reserved 1048576K

瞧,即使是垃圾收集器也有資訊顯示出來——在這個示例中,是關於退出和堆的。

這些都只是表面上的——還有更多選項可用於調整。

事實上,這個改進並不能解決 一切問題 。因為 JEP 關注於通過它提供基礎設施和改變一些(很多?那一定是所有 GC 訊息)已經存在的呼叫,而不是所有事情。雖然我找不到其它使用新機制的日誌,但它可能就在那裡。

命令列引數驗證

分享一件有趣的事情:Java 8 虛擬機器要在使用到命令列引數的值時才會驗證它們。不幸的是,這在應用程式的生命週期中可能會顯得有些遲了,我可以預見隨著潛在的錯誤而來的崩潰。來看一個例子:

java -cp out-mr/mr.jar -XX:BlockLayoutMinDiamondPercentage=120 ...Main

我不知道 BlockLayoutMinDiamondPercentage 有什麼作用(也懶得查),看起來 120不是一個有效的百分比。但 Java 8 沒有收到干擾,愉快地執行了 JAR 包中的程式碼——顯然這並不是程式執行所需要的值。也許 120 就是一個有效的值呢?Java 9 並不這麼看:

java9 -cp out-mr/mr.jar -XX:BlockLayoutMinDiamondPercentage=120 ...Main

intx BlockLayoutMinDiamondPercentage=120 is outside the allowed range [ 0 ... 100 ]
Improperly specified VM option 'BlockLayoutMinDiamondPercentage=120'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

不錯 ... JEP 245 為 Java 9 帶來了在開始執行時驗證所有輸入引數的能力。從上面的例子可以看到,它也輸出瞭解釋性的錯誤訊息。

相關推薦

JavaJDK9 內部探索——版本架構版本 jar 其他

JShell 因為已經有很多人在談論 Jigsaw,因此在第一部分我們先跳過不去講它。在這一部分我們將會照本宣科地拿 JShell 做些事情, 這是 Java 的一個全新的 REPL (說到它能做的事情,例如你在一個地方敲入了 Java 程式碼,有了它就可以馬上把程式碼

Java開發工具--Eclipse&MySQL官網自選版本下載以及專案jar下載

我們一般在使用開發軟體時,不一定使用最新版本的開發軟體,所以需要選擇適用的開發軟體來開發專案,下面是我總結的eclipse以及mysql官網自選版本下載步驟: Eclipse自選版本下載 百度輸入eclipse,進入eclipse官網地址,點選右上角的Down

java--泛型-型別擦除與型的衝突和解決方法

型別擦除與多型的衝突和解決方法 現在有這樣一個泛型類: [java] view plain copy print ? class Pair<T>&

javawebdriver selenium爬蟲html解析class名有空格

WebElement S_main = driver.findElement(By.className("S_main")); WebElement plc_main = S_main.findElement(By.id("plc_main")); WebElement S_

乾貨分散式記憶體資料庫新架構極速OLTP應用新利器

TimesTen Scaleout,它實際上是一款關係型資料庫,不過是在執行的期間,把資料全量載入到記憶體當中來進行實現。 Oracle TimesTen 先簡單的說一下TimesTen Scaleout的歷史,它實際上是一款關係型資料庫,不過是在執行的期間,把資料全量載入到記憶體當中來進行實現。Ti

Java-JSP九大內建物件作用分別是什麼? 分別有什麼方法?

一、pageContext表示頁容器     pageContext物件的作用是取得任何範圍的引數,通過pageContext物件可以獲取JSP頁面的out、request、response、session、application等物件,或者可以重新定向客戶的請求等,較少使

JAVA利用反射呼叫不同方法減少重複程式碼

今天在寫大作業的時候,遇到如下問題:整個方法裡只有資料獲取時的get方法不同,如何通過傳遞進來的不同的例項引數來使用不同的方法,而避免大段的程式碼copy,做到程式碼複用。於是今天粗略地瞭解了反射機制

Javai++與++i的不同從底層和效率上比較

以前書本、視訊和網站上但到i++和++i的區別,都是簡單,兩句話。 i++,先運算,後賦值 ++i,先賦值,後運算 舉個例子:(Java語言) int i = 1; System.out.print(i++); int j

JAVAapache poi excel 檔案讀取各種資料型別不規則excel格式都可以讀取

本文將通過例項來介紹apache poi  讀取excel的原理,包括各種資料型別的處理,本文提供的程式碼非常通用,即使不規則的excel檔案,也可以讀取。 直接看程式碼吧 package poi.excel; import java.io.File; import j

Java_SSM(四)Eclipse中通過maven引入jar

osc ati eight wid -- stat ack ips 技術 這篇博文我們介紹一下如何通過eclipse配置setting並引入jar包 (1)eclipse:Window--Preferences--Maven--User Setting 全部完成

安裝版本 cuda 版本之間切換

1. cuda 的下載與安裝方法選擇 到 CUDA Toolkit Download 下載所需版本,以 cuda_9.0.176_384.81_linux.run為例: 建議選擇使用 .run 檔案安裝,因為使用 .deb可能會將已經安裝的較新的顯示卡驅動替換。 2. c

主機ssh升級到6.7以上版本使用jsch jarssh連線不上報Algorithm negotiation fail問題的解決辦法

ssh連線問題是由於主機ssh中缺少與jsch jar包匹配的加密演算法導致,jsch jar包的預設加密演算法貌似是diffie-hellman-group-exchange-sha1。 在目標主機

javajava版本新特性總結

Java5: 1、泛型 Generics:         引用泛型之後,允許指定集合裡元素的型別,免去了強制型別轉換,並且能在編譯時刻進行型別檢查的好處。     &nb

javaKDTree實現個java版本留著日後可能用得上

Java版本KDTree 在KDTree中,只有n >> 2 ^ xn時,在明顯得有KDTCount << n, n是點的個數, xn是點的維數 KDTCount是在KDTree搜尋時計算距離的次數統計 package main; import

java架構演變學習

【前言】       之前專案上用的是dubbo的框架,不知道為什麼。 最近學習宜立方商城這個專案,視訊的老師有講。 在此總結記錄一下。 【正文】 1.傳統架構  適用於併發量小的情況下。 2.

Java關於String.intern()函式在JDK8 和 JDK9 下結果不同的問題

今天準備opentalk資料的時候,無意間發現一段很有意思的程式碼,特此記錄一下: /** * @author dxc * @date 2018/11/4 */ public class StringInternTest { public static vo

JAVA基於MVC架構Java技術薈萃案例演練

作者 白寧超 2016年6月9日22:47:08 閱讀前瞻:本文源於對javaweb相關技術和資料彙總,涉及大量javaweb基礎技術諸如:Servlet執行原理、Get/Post請求的區別、jsp的基本原理和執行框架、jsp的9大隱含物件的使用、MVC開發模式的使用、構建封裝自己dao程式碼庫

javaitoo項目實戰之hibernate 懶載入優化性能

bsp xtra extra pda 程序 前端框架 外連接 獲取 轉換成 在做itoo 3.0 的時候,考評系統想要上線,就開始導入數據了,僅僅導入學生2萬條數據,可是導入的速度特別的慢。這個慢的原因是由於導入的時候進行了過多的IO操作。可是導入成功之後,

javaitoo項目實戰之hibernate 批量保存優化

新的 hibernate 缺點 try 實戰 lis 插入 entity man 在itoo中。基本上每一個系統都有一個導入功能,大量的數據填寫進入excel模板中。然後使用導入功能導入的數據庫中,這樣能夠大大的提高工作效率。那麽導入就涉及到了批量保存數據庫的

Java滾動數組動態規劃UVA - 11137 - Ingenuous Cubrency

得到 lose math scanner light clas details 狀態 ann 滾動數組優化自己畫一下就明白了。 http://blog.csdn.net/u014800748/article/details/45849217 解題思路:本題利用遞推關系解決。