Java 9終于要包含Jigsaw項目了
當Jigsaw在Java 9中最終發布時,這個項目的歷史已經超過八年了。
在最初的幾年中,它必須要與另外兩個類似的Java規范請求(Java Specification Request)進行競爭,這兩個規范名為 JSR 277 Java模塊系統(Java Module System) 以及 JSR 294 增強的模塊化支持(Improved Modularity Support) 。它還導致了 與OSGi社區的沖突 ,人們擔心Jigsaw項目會成為不必要且不完備的功能性重復,逼迫Java開發人員必須在兩種互不兼容的模塊系統中做出選擇。
在早期,這個項目并沒有充足的人手,在2010年Sun并入Oracle的時候,甚至一度中斷。直到2011年,在Java中需要模塊系統的強烈需求被重申,這項工作才得到完全恢復。
接下來的三年是一個探索的階段,結束于2014年的7月,當時建立了多項Java增強提議( Java Enhancement Proposal),包括 JEP 200 模塊化JDK(Modular JDK) 、 JEP 201 模塊化源碼(Modular Source Code) 和 JEP 220 模塊化運行時鏡像(Modular Run-Time Image) ,以及最終的 JSR 376 Java平臺模塊系統(Java Platform Module System) 。上述的最后一項定義了真正的Java模塊系統,它將會在JDK中以一個新JEP的形式來實現。
在2015年7月,JDK劃分為哪些模塊已經大致確定(參見JEP 200),JDK的源碼也進行了重構來適應這種變化(參見JEP 201),運行時鏡像(run-time image)也為模塊化做好了準備(參見JEP 220)。所有的這些都可以在當前 JDK 9的預覽版 中看到。
針對JSR 376所開發的代碼很快將會 部署到JDK倉庫中 ,但是令人遺憾的是,現在模塊化系統本身尚無法體驗。(目前,Java 9的預覽版本已經包含了模塊化功能。——譯者注)
驅動力
在Jigsaw項目的歷史中,它的驅動力也發生過一些變化。最初,它只是想模塊化JDK。但是當人們意識到如果能夠在庫和應用程序的代碼中也使用該工具的話,將會帶來非常大的收益,于是它的范圍得到了擴展。
不斷增長且不可分割的Java運行時
Java運行時的大小在不斷地增長。但是在Java 8之前,我們并沒有辦法安裝JRE的子集。所有的Java安裝包中都會包含各種庫的分發版本,如XML、SQL以及Swing的API,不管我們是否需要它們,都要將其包含進來。
對于中等規模(如桌面PC和筆記本電腦)以上的計算設備來說,這不算是什么嚴重的問題,但是對于小型的設備來說,這就很嚴重了,比如在路由器、TV盒子和汽車上,還有其他使用Java的小地方。隨著當前容器化的趨勢,在服務器領域也有相關的要求,因為減少鏡像的大小就意味著降低成本。
Java 8引入了 compact profile 的功能,它們定義了三個Java SE的子集。在一定程度上緩解了這個問題,但是它們只有在嚴格限制的場景下才能發揮作用,profile過于死板,無法涵蓋現在和未來所有使用JRE部分功能的需求。
JAR/Classpath地獄
JAR地獄和Classpath地獄是一種詼諧的說法,指的是Java類加載機制的缺陷所引發的問題。尤其是在大型的應用中,它們可能會以各種方式產生令人痛苦的問題。有一些問題是因為其他的問題而引發的,而有一些則是獨立的。
無法表述依賴
JAR文件無法以一種JVM能夠理解的方式來表述它依賴于哪些其他的JAR。因此,就需要用戶手動識別并滿足這些依賴,這要求用戶閱讀文檔、找到正確的項目、下載JAR文件并將其添加到項目中。
而且,有一些依賴是可選的,只有用戶在使用特定功能的特性時,某個JAR才會依賴另外一個JAR。這會使得這個過程更加復雜。
Java運行時在實際使用某項依賴之前,并不能探測到這個依賴是無法滿足的。如果出現這種情況,將會出現 NoClassDefFoundError
異常,進而導致正在運行的應用崩潰。
像Maven這樣的構建工具能夠幫助解決這個問題。
傳遞性依賴
一個應用程序要運行起來可能只需依賴幾個庫就足夠了,但是這些庫又會需要一些其他的庫。問題組合起來會變得更加復雜,在所消耗的體力以及出錯的可能性上,它會呈指數級地增長。
同樣,構建工具能夠在這個問題上提供一些幫助。
遮蔽
有時候,在classpath的不同JAR包中可能會包含全限定名完全相同的類,比如我們使用同一個庫的兩個不同版本。因為類會從classpath中的第一個JAR包中加載,所以這個版本的變種將會“遮蔽”所有其他的版本,使它們變得不可用。
如果這些不同的變種在語義上有所差別,那將會導致各種級別的問題,從難以發現的不正常行為到非常嚴重的錯誤都是有可能的。更糟糕的是,問題的表現形式是不確定的。這取決于JAR文件在classpath中的順序。在不同的環境下,可能也會有所區別,例如開發人員的IDE與代碼最終運行的生產機器之間就可能有所差別。
版本沖突
如果項目中有兩個所需的庫依賴不同版本的第三個庫,那么將會產生這個問題。
如果這個庫的兩個版本都添加到classpath中的話,那么最終的行為是不可預知的。首先,因為前面所述的遮蔽問題,兩個版本的類中,只會有一個能夠加載進來。更糟糕的是,如果某個類位于一個JAR包中,但是它所訪問的其他類卻不在這個包中,這個類也能夠加載。所導致的結果就是,對這個庫的代碼調用將會混合在兩個版本之中。
在最好的情況下,如果試圖訪問所加載的類中不存在的代碼,將會導致明顯的 NoClassDefFoundError
錯誤。但是在最壞的情況下,版本之間的差別僅僅是在語義上,實際的行為會有細微的差別,這會引入很難發現的bug。
識別這種情況所導致的難以預料的行為是很困難的,也無法直接解決。
復雜的類加載機制
默認情況下,所有的類由同一個 ClassLoader
負責加載,在有些場景下,可能有必要引入額外的加載器,例如允許用戶加載新的類,對應用程序進行擴展。
這很快就會導致復雜的類加載機制,從而產生難以預期和難以理解的行為。
在包之間,只有很弱的封裝機制
如果類位于同一個包中,那Java的可見性修飾符提供了一種很棒的方式來實現這些類之間的封裝。但是,要跨越包之間邊界的話,那只能使用一種可見性: public 。
因為類加載器會將所有加載進來的包放在一起,public的類對其他所有的類都是可見的,因此,如果我們想創建一項功能,這項功能對某個JAR是可用的,而對于這個JAR之外是不可用的,這是沒有辦法實現的。
手動的安全性
包之間弱封裝性所帶來的一個直接結果就是,安全相關的功能將會暴露在同一個環境中的所有代碼面前。這意味著,惡意代碼有可能繞過安全限制,訪問關鍵的功能。
從Java 1.1開始,有一種hack的方式,能夠防止這種狀況:每當進入安全相關的代碼路徑時,將會調用 SecurityManager
,并判斷是不是允許訪問。更精確地講,它 應該在 每個這樣的路徑上都進行調用。過去,在有些地方遺漏了對它們的調用,從而出現了一些漏洞,這給Java帶來了困擾。
啟動性能
最后,Java運行時加載并JIT編譯全部所需的類需要較長的時間。其中一個原因在于類加載機制會對classpath下的所有JAR執行線性的掃描。類似的,在識別某個注解的使用情況時,需要探查classpath下所有的類。
目標
Jigsaw項目的目標就是解決上面所述的問題,它會引入一個語言級別的機制,用來模塊化大型的系統。這種機制將會用在JDK本身中,開發人員也可以將其用于自己的項目之中。
需要注意的是,對于JDK和我們開發人員來說,并不是所有的目標都具有相同的重要性。有一些與JDK具有更強的相關性,并且大多數都對日常的編程不會帶來巨大的影響(這與最近的語言修改形成了對比,如lambda表達式和默認方法)。不過,它們依然會改變大型項目的開發和部署。
可擴展性的平臺
JDK在模塊化之后,用戶就能挑出他們需要的功能,并創建自己的JRE,在這個JRE中只包含他們需要的模塊。這有助于在小型設備和容器領域中,保持Java作為關鍵參與者的地位。
在這個提議的規范中,允許將Java SE平臺及其實現分解為一組組件,開發人員可以把這些組件組裝起來,形成自定義的配置,里面只包含應用實際需要的功能。—— JSR 376
可靠的配置
通過這個規范,某個模塊能夠聲明對其他模塊的依賴。運行時環境能夠在編譯期(compile-time)、構建期(build-time)以及啟動期(launch-time)分析這些依賴,如果缺少依賴或依賴沖突的話,很快就會發生失敗。
強封裝
Jigsaw項目的一個主要目標就是讓模塊只導出特定的包,其他的包是模塊私有的。
模塊中的私有類就像是類中的私有域。換句話說,模塊的邊界不僅確定了類和接口的可見性,還定義了它的可訪問性。—— Mark Reinhold所撰寫的文章“Project Jigsaw:將宏偉藍圖轉換為可聚焦的點”
提升安全性和可維護性
在模塊中,內部API的強封裝會極大地提升安全性,因為核心代碼對于沒有必要使用它們的其余代碼來講是隱藏起來的。維護也會變得更加容易,這是因為我們能夠更容易地將模塊的公開API變得更小。
隨意使用Java SE平臺實現的內部API不僅有安全風險,而且也會帶來維護的負擔。該提議規范能夠提供強封裝性,這樣實現Java SE平臺的組件就能阻止對其內部API的訪問。 —— JSR 376
提升性能
因為能夠更加清晰地界定所使用代碼的邊界,現有的優化技術能夠更加高效地運用。
很多預先(ahead-of-time)優化和全程序(whole-program)優化的技術會更加高效,因為能夠得知某個類只會引用幾個特定組件中的類,它并不能引用運行時所加載的任意類。 —— JSR 376
核心概念
因為模塊化是目標,所以Jigsaw項目引入了 模塊(module) 的概念,描述如下:
命名、自描述的程序組件,會包含代碼和數據。模塊必須能夠包含Java類和接口,組織為包的形式,同時也能以動態加載庫的形式(dynamically-loadable library)包含原生代碼。模塊的數據必須能夠包含靜態資源文件和用戶可編輯的配置文件。 —— Java平臺模塊系統:需求(草案2)
為了能夠基于一定的上下文環境來了解模塊,我們可以想一下知名的庫,如 Google Guava 或 Apache Commons 中的庫(比如Collections或IO),將其作為模塊。根據作者希望劃分的粒度,每個庫都可能劃分為多個模塊。
對于應用來說也是如此。它可以作為一個單體(monolithic)的模塊,也可以進行拆分。在確定如何將其劃分為模塊時,項目的規模和內聚性將是重要的因素。
按照規劃,在組織代碼時,模塊將會成為開發人員工具箱中的常規工具。
開發人員目前已經能夠考慮到一些標準的程序組件,如語言層面的類和接口。模塊將會是另外一種程序組件,像類和接口一樣,它們將會在程序開發的各個階段發揮作用。 —— Mark Reinhold的文章“Project Jigsaw:將宏偉藍圖轉換為可聚焦的點”
模塊又可以進一步組合為開發階段的各種配置,這些階段也就是編譯期、構建期、安裝期以及運行期。對于我們這樣的Java用戶來說,可以這樣做(在這種情況下,通常會將其稱之為 開發者模塊 ),同時這種方式還可以用來剖析Java運行時本身(此時,它們通常稱之為 平臺模塊 )。
實際上,這就是JDK目前進行模塊化的規劃。
(點擊放大圖像)
特性
那么,模塊是如何運行的呢?查閱一下 Jigsaw項目的需求 以及 JSR 376 將會幫助我們對其有所了解。
依賴管理
為了解決“JAR/Classpath地獄”的問題,Jigsaw項目的一個關鍵特性就是依賴管理。讓我們看一下這些相關的組件。
聲明與解析
模塊將會聲明它需要哪些其他的模塊 才能編譯和運行。模塊系統會使用該信息 傳遞性地識別所有需要的模塊 ,從而保證初始的那個模塊能夠編譯和運行。
我們還可以不依賴具體的模塊,而是依賴一組接口。模塊系統將會試圖據此 識別模塊 , 這些模塊 實現了所依賴的接口 , 能夠滿足依賴 , 系統會將其綁定到對應的接口中。
版本化
模塊 將會進行 版本化 。它們能夠標記自己的版本(在很大程度上可以是任意格式,只要能夠完全表示順序就行),版本還能用于限制依賴。在任意階段都能覆蓋這兩部分信息。模塊系統會在各個階段都強制要求配置能夠滿足所有的限制。
Jigsaw項目不一定會支持在一個配置中存在某個模塊的多個版本。但是,稍等,那該如何解決JAR地獄的問題呢? 好問題!
版本選擇——針對同一個模塊,在一組不同版本中挑選最合適的版本——并沒有作為規范所要完成的任務。所以,在我撰寫的上文中,模塊系統會識別所需的模塊進行編譯,在運行時則可能會使用另外一個模塊,這都基于一個假設,那就是環境中只存在模塊的一個版本。如果存在多個版本的話,那么上游的步驟(如開發人員或者他所使用的構建工具)必須要做出選擇,系統只會校驗它能滿足所有的約束。
封裝
模塊系統會在各個階段強制要求強封裝。這是圍繞著一個導出機制實現的,在這種情況下,只有模塊導出的包才能訪問。封裝與 SecurityManager
所執行的安全檢查是相獨立的。
這個提議的具體語法尚沒有定義,但是 JEP 200 提供了一些關鍵語義的XML實例。作為樣例,如下的代碼聲明了 java.sql
模塊。
<module>
<!-- 模塊的名字 -->
<name>java.sql</name>
<!-- 每個模塊都會依賴java.base -->
<depend>java.base</depend>
<!-- 這個模塊依賴于java.logging和java.xml
模塊,并重新導出這些模塊所導出的API包 -->
<depend re-exports="true">java.logging</depend>
<depend re-exports="true">java.xml</depend>
<!-- 這個模塊導出java.sql、javax.sql以及
javax.transaction.xa包給其他任意的模塊 -->
<export><name>java.sql</name></export>
<export><name>javax.sql</name></export>
<export><name>javax.transaction.xa</name></export>
</module></code></pre>
從這個代碼片段我們可以看出,java.sql依賴于 java.base
、 java.logging
以及 java.xml
。在稍后介紹不同的導出機制時,我們就能理解上文中其他的聲明了。
導出
模塊會 聲明特定的包 進行導出,只有包含在這些包中的類型才能導出。這意味著其他模塊只能看到和使用這些類型。更嚴格是, 其他模塊必須要顯式聲明依賴包含這些類型的模塊,這些類型才能導出到對應的模塊中 。
非常有意思的是,不同的模塊能夠 包含相同名稱的包 ,這些模塊甚至還能夠將其 導出 。
在上面的樣例中, java.sql
導出了 java.sql
、 javax.sql
以及 javax.transaction.xa
這些包。
重新導出
我們還能夠在某個模塊中重新導出它所依賴的模塊中的API(或者是其中的一部分)。這將會對 重構 提供支持,我們能夠在不破壞依賴的情況下拆分或合并模塊,因為最初的依賴可以繼續存在。重構后的模塊可以導出與之前相同的包,即便它們可能不會包含所有的代碼。在極端的情況下,有一種所謂的 聚合器模塊(aggregator module) ,它可以根本不包含任何代碼,只是作為一組模塊的抽象。實際上,Java 8中所提供的compact profile就是這樣做的。
從上面的例子中,我們可以看到 java.sql
重新導出了它依賴的API,即 java.logging
和 java.xml
。
限制導出
為了幫助開發者(尤其是模塊化JDK的人員)讓他們所導出API的有較小的接觸面,有一種可選的 限制導出(qualified export) 機制,它允許某個模塊將一些包聲明為只針對一組特定的模塊進行導出。所以使用“標準”機制時,導出功能的模塊并不知道(也不關心)誰會訪問這些包,但是通過限制導出機制,能夠讓一個模塊限定可能產生的依賴。
配置、階段以及保真性(Fidelity)
如前所述, JEP 200的目標之一 就是模塊能夠在開發的各個階段組合為各種配置。對于平臺模塊可以如此,這樣就能夠創建與完整JRE或JDK類似的鏡像,Java 8所引入的compact profile以及包含特定模塊集合(及其級聯依賴)的任意自定義配置都使用了這種機制。類似的,開發人員也可以使用這種機制來組合他們應用程序的不同變種。
在 編譯期(compile-time) ,要編譯的代碼只能看到所配置的模塊集合中導出的包。在 構建期(build-time) ,借助一個新的工具(可能會被稱為 JLink ),我們能夠創建只包含特定模塊及其依賴的二進制運行時鏡像。在 安裝期(launch-time) ,鏡像能夠看起來就像是只包含了它所具有的模塊的一個子集。
我們還能夠 替換 實現了 授權標準(endorsed standard) 和 獨立技術(standalone technology) 的模塊,在任意的階段都能將其替換為較新的版本。這將會替代已廢棄的授權標準重載機制(endorsed standards override mechanism)以及擴展機制(參見下文。)
模塊系統的各個方面(如依賴管理、封裝等等),在 所有階段的運行方式是完全相同的 ,除非因為特定的原因,在某些階段無法實現。
模塊相關的所有信息(如版本、依賴以及包導出)都會在代碼文件中進行描述,這樣會獨立于IDE和構建工具。
性能
全程序優化的技術
在模塊系統中,借助強封裝技術,能夠很容易自動計算出一段特定的代碼都用在了哪些地方。這會使得程序分析和優化技術更加可行:
快速查找JDK和應用程序的類;及早進行字節碼的檢驗;積極級聯(aggressive inlining)像lambda表達式這樣的內容以及其他的編譯器優化;構建特定于JVM的內存鏡像,它加載時能夠比類文件更加高效;預先將方法體編譯為原生代碼;移除沒有用到的域、方法和類。—— Jigsaw項目: 目標 & 需求(草案3)
有一些被稱為 全程序優化(whole-program optimization)的技術 ,在Java 9中至少會實現兩種這樣的技術。還有包含一個工具,使用這個工具能夠分析給定的一組模塊,并使用上述的優化技術,創建更加高性能的二進制鏡像。
注解
目前,要自動發現帶有注解的類(如Spring注解標注的配置類),需要掃描特定包下的所有類。這通常會在程序啟動的時候完成,這在相當程度上會減慢啟動的過程。
模塊將會提供一個API,允許調用者識別所有帶有給定注解的類。 一種預期的方式 是為這樣的類創建索引,這個索引會在模塊編譯的時候創建。
與已有的概念和工具集成
診斷工具(如棧跟蹤信息) 將會進行更新 ,其中會包含模塊的信息。而且,它們還會集成到反射API中,這樣就能按照操作類的方式來使用它們,還會包含 版本信息 ,這一信息可以進行反射,也可以 在運行時重載 。
模塊的設計能夠讓我們在使用 構建工具 時“盡可能地減少麻煩(with a minimum of fuss)”。編譯之后的模塊能夠用在classpath中,也能作為一個模塊來使用,這樣的話,庫的開發人員就沒有必要為classpath應用和基于模塊的應用分別創建 多個構件 了。
與其他模塊系統的 相互操作 也進行了規劃,這其中最著名的也就是OSGi。
盡管模塊能夠對其他的模塊隱藏包,但是我們依然能夠對模塊包含的類和接口執行 白盒測試 。
特定OS的包
模塊系統在設計時,始終考慮到了 包管理器文件格式 ,“如RPM、Debian以及Solaris IPS”。開發人員不僅能夠使用已有的工具將一組模塊集合創建為特定OS的包,這些模塊還能調用按照相同機制安裝的其他模塊。
開發人員還能夠將 組成應用的一組模塊打包為 特定OS的包,“終端用戶能夠按照目標系統的通用做法,安裝和調用所打成的包”。基于上述的介紹,我們可以得知只有目標系統中不存在的模塊才必須要打包進來。
動態配置
正在運行中的應用能夠 創建、運行并發布獨立的模塊配置 。在這些配置中,可以包含開發者和平臺模塊。對于容器類架構,這會非常有用,如IDE、應用服務器或其他Java EE平臺。
不兼容性
按照Java的慣例,這些變更在實現時,會強烈關注到向后的兼容性,所有標準和非廢棄的API及機制都能夠繼續使用。但是項目可能會依賴其他缺乏文檔的構造,這樣的話,在往Java 9遷移的時候,就需要一些額外的工作了。
內部API不可用了
借助于強封裝,每個模塊能夠明確聲明哪些類型會作為其API的一部分。JDK將會使用這個特性來封裝所有的內部API,因此它們會變得不可用了。
在Java 9所帶來的不兼容性中,這可能是涵蓋范圍最大的一部分。但是這也是最明顯的,因為它會導致編譯錯誤。
那么,什么是內部API呢?毫無疑問,位于 sun.*
包中的所有內容。如果位于 com.sun.*
包中,或者使用了 @jdk.Exported
注解,在Oracle JDK中它依然是可用的,如果沒有注解的話,那么它就是不可用的了。
能產生特殊問題的一個樣例就是 sun.misc.Unsafe
類。它用在了很多項目中,用來實現關鍵任務或性能要求較高的代碼,它將來可能 不可用 引發了 很多 的 相關討論 。不過,在 一次相關的交流中 曾經提出,通過一個 廢棄的命令行標記,它依然是可用的 。考慮到無法將其所有的功能都放到公開API中,這可能是一種必要的權衡。
另外一個樣例是 com.sun.javafx.*
包中的所有內容。這些類對于構建JavaFX控件是至關重要的,并且它們還有一定數量的bug要修改。這些類中的大多數功能 都會作為發布的目標 。
合并JDK和JRE
在具有可擴展的Java運行時之后,它允許我們很靈活地創建運行時鏡像,JDK和JRE就喪失了其獨有的特性,它們只是模塊組合中的兩種形式而已。
這意味著,這兩個構件將會具有相同的結構,包括目錄結構也相同,任何依賴它(如在原來的JDK目錄中會有名為jre的子目錄)的代碼就不能正常運行了。
內部JAR不可用了
像 lib/rt.jar
和 lib/tools.jar
這樣的內部JAR將不可用了。它們的內容將會存儲到特定實現的文件中,這些文件的格式還未明確說明,有可能會發生變化。
任何假設這些文件存在的代碼將無法正確運行。這可能對IDE或其他嚴重依賴這些文件的工具帶來一些切換的麻煩。
針對運行時鏡像內容的新URL模式
在運行時,有些API會返回針對類和資源文件的URL(如 ClassLoader.getSystemResource )。在Java 9之前,它們都是 jar URL ,格式如下:
jar:file:<path-to-jar>!<path-to-file-in-jar>
Jigsaw項目將會使用模塊作為代碼文件的容器,單個JAR將不可用了。這需要一個新的格式,所以這些API將會返回 jrt URL :
jrt:/<module-name>/<path-to-file-in-module>
如果使用這些API所返回的實例來訪問文件的代碼(如 URL.getContent ),那么運行方式會和現在一樣。但是,如果依賴于jar URL的 結構 (比如手動構建它們或對其進行解析),那么就會出錯了。
移除授權標準重載機制
有一些Java API被稱為“ 獨立技術(Standalone Technology) ”,它們的創建是在Java Community Process(如 JAXB )之外的。對它們來說,有可能會升級其依賴或使用替代實現。 授權標準重載機制 允許在JDK中安裝這些標準的替代版本。
這種機制在Java 8中已經廢棄了,在Java 9中將會移除,會由上文所述的可升級模塊來替代。
移除擴展機制
借助 擴展機制 ,自定義API能夠被JDK中運行的所有應用程序使用,而不必在classpath中對其進行命名。
這種機制在Java 8中已經廢棄了,在Java 9中將會移除。有些本身有用的特性將會保留。
接下來要做什么?
我們已經簡要了解了Jigsaw項目的歷史,看到是什么在驅動它的發展并討論了它的目標,如何通過一些特性來實現這些目標。除了等待Java 9以外,我們還能做些什么呢?
準備
我們應該為自己的項目做一些準備工作,檢查它們是否依賴Java 9中將要移除的內容。
至少,在檢查內部API依賴方面不再需要手動搜索了。從Java 8開始,JDK包含了Java依賴分析工具(Java Dependency Analysis Tool),名為 JDeps ( 介紹了一些內部的包 ,官方有針對 Windows 以及 Unix 的文檔),它能夠列出某個項目依賴的所有的包。如果在運行時使用- jdkinternals
參數的話,那么它將會列出該項目所使用的幾乎所有的內部API。
之所以說“幾乎所有”是因為它還無法識別Java 9中不可用的所有的包。這至少會影響到JavaFX所屬的包,可以查看 JDK-8077349 。( 通過使用這個搜索 ,除了缺失的功能以外,我沒能發現其他的缺陷。)
至少存在三個用于Maven的JDeps插件:分別由 Apache 、 Philippe Marschall 以及 我本人 所提供。就目前來講,最后一個是唯一當 jdeps
- jdkinternals
報告中依賴內部API時,導致構建失敗的插件。(現在,Apache的插件在出現內部API依賴時,也會提示構建失敗,參見InfoQ的這篇新聞。——譯者注)
討論
Jigsaw項目最新的消息來源于 Jigsaw-Dev郵件列表 。我也會在 博客 中繼續討論這個話題。
如果你擔心某個特定的API在Java 9中不可用的話,那么你可以查看 相關OpenJDK項目的郵件列表 ,因為他們會負責開發公開的版本。
采用
Java 9的早期試用構建版本 已經可用了。不過,JSR 376依然處于開發階段,在這些構建版本中尚無法使用模塊系統,還會有很多的變化。(在目前的試用版中,已經包含了Jigsaw,不過最新的消息是Java 9又要延期六個月發布了。——譯者注)實際上,除了強封裝以外,其他的功能都已經就緒了。
將收集到的消息發送給Jigsaw-Dev郵件列表能夠反饋給項目。最后,引用JEP 220(臨近)結尾的一段話:
我們不可能抽象地確定這些變更的全部影響,所以必須要依賴廣泛的內部測試,尤其重要的還有外部測試。[……]如果有些變更會給開發人員、部署人員或終端用戶帶來難以承受的負擔,那么我們將會研究減少其影響的方式。
另外,還有一個全球的Java用戶群組 AdoptOpenJDK ,它能夠很好地將早期試用者聯系起來。
關于作者
Nicolai Parlog 是一名軟件開發人員,對Java充滿熱情。他不斷地閱讀、思考以及撰寫與Java相關的內容,他靠編碼為生,也以此為樂。他是多個開源項目的長期貢獻者,并在 CodeFX 上用博客記錄軟件開發相關的內容。你可以在 推ter 上關注Nicolai。
來自: http://www.infoq.com/cn/articles/Project-Jigsaw-Coming-in-Java-9