顯式模組、自動模組


許多程式庫都還沒有模組化,為了相容性,是可以將這些程式庫的 JAR 放在類別路徑之中,但是對於採用模組化,明確定義了模組並放在模組路徑中,這樣的模組稱為顯式模組(Explicit module),顯式模組無法依賴在未命名模組,因為未具名模組並沒有名稱,無法在顯式模組的模組描述檔中進行 requires,如果你的程式碼中得使用未具名模組的類別,編譯時期就會找不到類別了。

若是採模組化設計,可以將未支援模組化設計的 JAR 檔案放在模組路徑,這會使得該 JAR 檔案被視為自動模組(Automatic module),自動模組也是具名模組的一種,稍後會看到名稱產生的規則,有了模組名稱之後,就可以 requires 自動模組,也就可以使用自動模組中公開的類別、方法與值域。

基於相容性,自動模組有隱含的模組定義,可以讀取其他模組,其他模組也可以讀取自動模組,應用程式在遷移至模組化設計的過程中,自動模組會是未具名模組至顯式模組之間的橋樑。

顯式模組、自動模組

並不是任何 JAR 都可以自動產生正確的模組名稱,既有的 JAR 若還沒有任何調整下,預設是基於檔名來產生名稱,產生的規則會是:

  • 取得 JAR 的主檔名

    若是 cc.openhome-1.0.jar 的話,就取得 cc.openhome-1.0 這個名稱。

  • 去除版本號

    版本號必須是連字號(-)或底線()後跟隨著數字,找到版本號之後,取得連字號(-)或底線()前的名稱,例如 cc.openhome.util-1.0 的話,就使用 cc.openhome.util,cc-openhome-util_1.0 的話,就使用 cc-openhome-util;如果沒有版本號的話,例如 cc_openhome_util,就直接使用該名稱。

  • 替換名稱中非字母部份為句號(.)

    因此對於 cc.openhome.util、cc-openhome-util 或 cc_openhome_util,最後決定出來的自動模組名稱都會是 cc.openhome.util。

在產生自動模組名稱時,JAR 主檔名不能有多個版本號區段,例如 cc.openhome.util_1.0-spec-1.0 的話,無法自動產生正確的模組名稱,此時若被放到模組路徑的JAR檔案,編譯時期沒有名稱可以 requires,而執行時期會產生 IllegalArgumentException,從而使得JVM無法初始模組層而發生 FindException

若不想基於檔名決定自動模組名稱,既有的 JAR 中,可以在 META-INF/MANIFEST.MF 裏增加 Automatic-Module-Name,指定自動模組名稱,然而對於第三方程式庫的既有 JAR,不建議自己做這個動作,最好是讓第三方程式庫的釋出者決定自動模組名稱,免得以後產生名稱上的困擾。

程式庫官方還沒決定自動模組名稱之前,依檔名來產生模組名稱實際上也會引發問題,有興趣瞭解的話,可參考〈Java SE 9 - JPMS automatic modules〉的內容。

在決定自己的應用程式是否遷移至模組化之前,看看使用到的各程式庫官方是不是都決定好(自動)模組名稱了,可以免去後續自行修改模組名稱的麻煩。

如果同一個套件出現在模組路徑上多個既有的 JAR 檔案中,由於一個套件不能出現在多個模組,因此只有其中一個 JAR 能成為自動模組,而其他會被忽略。