探祕Java9

凌峰發表於2018-03-08

2017年9月Java9正式釋出,之前就一直聽說新版會有模組化,仔細瞭解下Java9的發展史,這個模組化確實比較坎坷,當然,好事多磨嘛。

1、相關組織

JUG:Java User Groups(Java使用者群),以下是JUG官方提供的組織列表,其中有兩個是大陸的,一個在南京,一個在杭州,之前在南京時參加過南京JUG組織的活動。

JCP:Java Community Process,一個促進Java發展的國際組織,主要負責JSR的制定,OpenJDK的開發。其中JUG屬於JCP。

EC:Executive Committee,是JCP中的執行委員會,是選舉產生的,但Oracle是終身的執行委員會(沒辦法,因為JCP也是由SUN(後被Oracle並了)發起的),主要負責JSR的制定,有投票權。這裡列一下曾經的EC成員:Motorola、Nokia、Sony、Samsung、HP、Siemens、Texas Instruments、Apple、Philips、Symbian、JBoss、Google、Ericsson、BenQ、SpringSource、AT&T、VMWare、Aplix、Freescale、Apache、Doug Lea、Timothy Peierls。

2、相關名詞

JEP:JDK Enhancement Proposals(JDK增強建議),來源於JCP社群,但不一定被採納。

JSR:Java Specification Requests(Java規範請求),JSR是有狀態的,並不是所有的JSR都有效,所以在看JSR時需要先看下狀態是否有效。Java的各個版本的語言規範和虛擬機器規範都是JSR範疇裡的,JSR的生效由Expert Group(專家組)商討制定並由EC投票確立。JSR的確立是有一個具體流程規範的,不過並不是所有的JSR都會在JDK裡實現的。

JSR專家組(Expert Group):從JCP裡選出的對應領域有威望的個人(其實背後代表的是所屬公司),負責制定和修改JSR。其中Java9對應的JSR379的專家組如下:

Java語言規範:其實已經包括在JSR裡,細分開是因為只是語言層面的,不涉及跨平臺的JVM的細節,所以想要詳細瞭解Java語法的可以仔細研讀下。具體程式碼裡如何實現的不在規範裡。

JVM規範:這裡主要描述虛擬機器的實現規範,包括指令集及其作用、虛擬機器記憶體模型、類檔案描述、編譯、連結、載入、初始化等步聚描述,想要了解虛擬機器具體是怎麼工作的可以仔細研讀下,不過規範不涉及實現,目前虛擬機器的實現也有很多種,HotSpot是OpenJDK裡的,想要了解實現細節的可以下載HotSpot原始碼看下。

3、JDK功能的由來

通過上面的一些簡介可以大致看出,JDK的功能來源於Java開發者在實際使用時發現的一些不足之處,然後以JEP的方式反饋給社群,社群再通過專家組收集並制定JSR,再由EC投票是否要採納,對於規劃到Java版本JSR裡的再由JCP分配或認領開發實現,經過一系列測試驗證後釋出Release版本。

4、JSR376:JPMS

Java9的規範是JSR379,但379又依賴JSR376,也就是Java的平臺模組化,在JDK9的原始碼裡也可以看到“@spec JPMS”,這個表示的是這塊程式碼是JSR376裡要求實現或修改的。

5、JSR 379: JavaTM SE 9 Release Contents涉及哪些JEP?

個人根據JSR文件整理了下,共涉及91個JEP,其中8個JEP是關於廢棄的,39個JEP是關於修改的,44個JEP是關於新增的,模組化涉及8個JEP,安全涉及7個JEP。可以看出Java9不僅僅是模組化,還帶來很多其他的改變,具體整理JEP如下(前輟說明:U:修改,A:新增,D:廢棄,M:模組化,S:安全):

U  102: Process API Updates
A  110: HTTP 2 Client
U  143: Improve Contended Locking
U  158: Unified JVM Logging
U  165: Compiler Control
U  193: Variable Handles
U  197: Segmented Code Cache
U  199: Smart Java Compilation, Phase Two
AM 200: The Modular JDK
AM 201: Modular Source Code
A  211: Elide Deprecation Warnings on Import Statements
A  212: Resolve Lint and Doclint Warnings
U  213: Milling Project Coin
D  214: Remove GC Combinations Deprecated in JDK 8
A  215: Tiered Attribution for javac
U  216: Process Import Statements Correctly
U  217: Annotations Pipeline 2.0
A  219: Datagram Transport Layer Security (DTLS)
AM 220: Modular Run-Time Images
A  221: Simplified Doclet API
A  222: jshell: The Java Shell (Read-Eval-Print Loop)
A  223: New Version-String Scheme
U  224: HTML5 Javadoc
A  225: Javadoc Search
A  226: UTF-8 Property Files
A  227: Unicode 7.0
A  228: Add More Diagnostic Commands
US 229: Create PKCS12 Keystores by Default
D  231: Remove Launch-Time JRE Version Selection
U  232: Improve Secure Application Performance
A  233: Generate Run-Time Compiler Tests Automatically
A  235: Test Class-File Attributes Generated by javac
A  236: Parser API for Nashorn
A  237: Linux/AArch64 Port
U  238: Multi-Release JAR Files
D  240: Remove the JVM TI hprof Agent
D  241: Remove the jhat Tool
A  243: Java-Level JVM Compiler Interface
US 244: TLS Application-Layer Protocol Negotiation Extension
U  245: Validate JVM Command-Line Flag Arguments
US 246: Leverage CPU Instructions for GHASH and RSA
U  247: Compile for Older Platform Versions
U  248: Make G1 the Default Garbage Collector
AS 249: OCSP Stapling for TLS
U  250: Store Interned Strings in CDS Archives
A  251: Multi-Resolution Images
U  252: Use CLDR Locale Data by Default
A  253: Prepare JavaFX UI Controls & CSS APIs for Modularization
U  254: Compact Strings
U  255: Merge Selected Xerces 2.11.0 Updates into JAXP
U  256: BeanInfo Annotations
U  257: Update JavaFX/Media to Newer Version of GStreamer
U  258: HarfBuzz Font-Layout Engine
A  259: Stack-Walking API
UM 260: Encapsulate Most Internal APIs
AM 261: Module System
U  262: TIFF Image I/O
A  263: HiDPI Graphics on Windows and Linux
A  264: Platform Logging API and Service
U  265: Marlin Graphics Renderer
U  266: More Concurrency Updates
A  267: Unicode 8.0
A  268: XML Catalogs
A  269: Convenience Factory Methods for Collections
U  270: Reserved Stack Areas for Critical Sections
U  271: Unified GC Logging
A  272: Platform-Specific Desktop Features
A  273: DRBG-Based SecureRandom Implementations
U  274: Enhanced Method Handles
AM 275: Modular Java Application Packaging
AM 276: Dynamic Linking of Language-Defined Object Models
U  277: Enhanced Deprecation
A  278: Additional Tests for Humongous Objects in G1
U  279: Improve Test-Failure Troubleshooting
U  280: Indify String Concatenation
A  281: HotSpot C++ Unit-Test Framework
AM 282: jlink: The Java Linker
A  283: Enable GTK 3 on Linux
U  284: New HotSpot Build System
A  285: Spin-Wait Hints
AS 287: SHA-3 Hash Algorithms
DS 288: Disable SHA-1 Certificates
D  289: Deprecate the Applet API
AS 290: Filter Incoming Serialization Data
D  291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector
A  292: Implement Selected ECMAScript 6 Features in Nashorn
A  294: Linux/s390x Port
A  295: Ahead-of-Time Compilation
U  297: Unified arm32/arm64 Port
D  298: Remove Demos and Samples
U  299: Reorganize Documentation

6、Java9帶來哪些變化?

通過5中的JEP也可以看出有9帶來了哪些變化,不過官方還是給了一個分類如下:

主要分為:平臺、語言、核心庫、網路、安全、客戶端庫、擴充標記語言 這7類。

7、關於模組化

因為Java9對於平臺來說最大的變化是模組,涉及到了語法規範和虛擬機器的改變,具體有哪些變化呢?其實規範裡這些都特意標出來了,按照常規的思考應該類載入會變,還要就是要麼像OSGI那樣用MANIFEST.MF,要麼就新增加一些關鍵字。實際是增加了一個module-info.java檔案,這個有點像已經有的package-info.java,不過package-info.java其實只起到註釋包的作用,並沒有什麼新的關鍵字,所以沒有語法不相容的情況,但module-info.java則不同了,個人感覺和OSGI裡的MANIFEST.MF裡的一些用法並沒有什麼不同,但這樣會導致IDE識別不了這些關鍵字,編譯器就需要有對應的修改才能正常相容。

其實模組化這個想法早在十幾年前就已經提出來了,而且也有對應的JSR,因為在構建大型的Java應用時會因為使用的Jar有多個版本,根據路徑載入的方式會出現不可控的情況,也就是我們常見的類衝突,因為不同的環境可能會導致不同的類載入順序,而Java對於相同包名類名的類載入只有第一次生效,後面的不會再載入,所以對於大型系統的複雜依賴這個問題比較嚴重。還有就是生成的應用越來越大,在嵌入式應用中不太適合。而OSGI最開始也不是模組化的代名詞,其實OSGI最開始創立的目的應該是像JCP一樣,制定一些閘道器裝置相關規範的,那時Java在嵌入式領域也有了廣泛的應用,當時看到了Java的不足,提出來JSR291,這才誕生了OSGI框架,經過十多年的發展,已經相當成熟。

不過JSR376也說明了自己與JSR291的區別,JSR291是在平臺之上的,不是平臺具備的能力,JSR376的目的是讓平臺具有模組化的能力,同時平臺的模組化能力也能夠直接給OSGI框架使用,畢竟OSGI的核心是動態載入的框架。

8、其他關於模組化的應用

OSGI:為什麼OSGI可以直接基於現有的JDK達到模組化?其實這個依賴於Java的類載入機制,不同的ClassLoader是可以讓同一個類有多個版本載入的,但同一個ClassLoader不能對同一個類的多個版本進行載入。

Pandora:其實這個我覺得應該算是模組化的產物,如果十多年前模組化被納入JDK,也不會有Pandora了吧。實現的原理也是基於類的載入和對應的ClassLoader有關。

Maven:也算是模組化的應用吧,不過是以pom.xml的方式來管理依賴的,對於衝突也是在pom.xml的依賴管理裡來排,但對於像OSGI和Pandora那樣的類載入方式卻不涉及,完全靠人肉排除多版本依賴的問題。不過我想Maven的目的並不僅僅是解決這個問題的,Maven主要還是管理依賴和jar包分發,從更上層來避免此類衝突問題。


相關文章