Java 9 Modularity 關鍵字整理

模組這件事其實不是甚麼新鮮的技術了,早在JavaScript, Python等等語言就有了,而Java也終於在JDK9.0釋出了Modularity。在模組出來以前,Java的封裝一直是很頭疼的問題,基本上都是包裝成jar檔,裡面有package,package裏頭的修飾詞有public、default、protected、private。

Modifier  Class Package Subclass  World
public  Y  Y Y Y
protected  Y  Y Y N
default (no modifier)  Y  Y N N
private  Y N N N

這樣的封裝有一個很大的問題。如果我有一個類別A,它被放置com.my.package,而我又有一個類別B,它被放置在com.my.package.inner,A可以被其他package存取,但B是非公開的,同時A也要可以存取B的內容。這時會發現B的修飾詞不知道該放甚麼了,因為唯一可以被自己以外的package讀到的修飾詞就只有public,而本來用意只是想給com.my.package使用的B,現在變成所有人都可以讀取了,這並不是我們一開始想要的結果。

Java 9 的模組化給了我們這個彈性。透過模組,我們可以更準確的指定哪些package是可以被”看見”的,又哪些模組、類別是要被依賴使用的。這一切的魔法都在module-info.java這個敘述檔裡去聲明。以下針對這個檔裡面幾個新的關鍵字做整理。

module module.name  : 宣告一個模組名稱 (為避免撞名,建議用reversed domain name as namespace)

exports pkg.name : 輸出package (這個模組裡,哪些package是可以被”看見”的)

export pkg.name to module.name : 只輸出該package給針對的模組使用 (只有指定的module可以”看見”該package)

以上只是針對一個模組聲明哪些package可以被使用,如果要使用這個模組,要在module-info裡面加上下:

requires module.name : 需要該module

requires transitive module.name : 所有依賴當下module自動也依賴該module

假設我們兩個模組名稱分別是one和two。one裡面有com.my.package和com.my.package.inner以及上述的A、B類別。一個最簡單的module-info.java如下:

module one{
    exports com.my.package;
}

two裡面我們有com.fun.package,package裡面有隻C類別。則:

module two{
    exports com.fun.package;
    requires transitive one;
}

這樣子,我們就可以在module two的C類別裡面,正常的引用module one裡的A類別,但同時我們是看不到類別B的。這看似符合了我們一開始的封裝需求。注意transitive這個關鍵字,假設有另一個module three引用了module two,如果有transitive,那它會自動requires module one。反之,如果沒有的話,那module three會看不到所有module one裡面的東西。在封裝層面上,這樣的設計賦予了更多的彈性。

還有一種封裝狀況是介面實作。在依賴裡面我們只提供介面,而真正的實作沒必要顯露出來給使用方,這時候我們可以用以下關鍵字:

provides class.name with class.name.impl : 提供介面和實作類別 (service provider)

uses class.name : 使用類別 (通常為抽象介面) (service consumer)

最後一個封裝問題是Java reflection,儘管修飾詞是private,透過reflection我們還是可以存取到private的內容。但在Java9的模組管理下,reflection access就不再被允許,但如果真的有需要,還是可以透過以下關鍵字:

open module.name : 允許對該模組用reflection access

opens pkg.name : 允許對該package用reflection access

opens pkg.name to module.name 只允許對該package在針對的module下用reflection access

目前幾個常用的關鍵字如上,Java 9的模組化主要強調的是更好的封裝(strong encapsulation),它並沒有要嘗試解決一些library或版本依賴性的問題,那些問題或許在以往的gradle或maven已經有許多不錯的方法了。最後,要從非模組化轉移到模組化無非是一項工程,尤其是如果又用到一些沒有模組化的library又該怎麼辦,或是無法相容的library…等等的問號,只能說要等到碰到才會依依去找解法吧ㄎㄎ。

參考:

  • https://www.oracle.com/corporate/features/understanding-java-9-modules.html
  • http://files.zeroturnaround.com/pdf/RebelLabs-Java-9-modules-cheat-sheet.pdf
  • Java 9 Module Services
  • https://www.amazon.com/Java-Modularity-Developing-Maintainable-Applications/dp/1491954167

Leave a Reply

avatar