Java 9 平臺(tái)級(jí)模塊系統(tǒng)

模塊化是 Java 9 一個(gè)非常重要的特性,終于有時(shí)間整理一下這方面的內(nèi)容了。

模塊化是軟件工程中非常重要的一個(gè)概念。把獨(dú)立的功能封裝成模塊,并提供接口供外部使用是我們?cè)陂_發(fā)中努力實(shí)現(xiàn)的目標(biāo)。模塊化有很多好處:

  • 代碼內(nèi)聚,容易維護(hù);
  • 能夠有效降低復(fù)雜度;
  • 能提供更好的伸縮性和擴(kuò)展性。

Java 9 的 Jigsaw 項(xiàng)目致力于為 Java 9 帶來平臺(tái)級(jí)的模塊化系統(tǒng)。這個(gè)項(xiàng)目從 2008 年就已經(jīng)開始,由于很多原因一直沒有發(fā)布?,F(xiàn)在,Jigsaw 涵蓋了 6 個(gè) JEP,終于作為 Java 9 的一部分發(fā)布出來。

從整體到模塊

Java 一直堅(jiān)持向后兼容,每更新一個(gè)版本,都變得更大更復(fù)雜。在過去的 JDK 版本中,沒有強(qiáng)制要求模塊化,使得 Java 平臺(tái)和 JDK 越來越讓人糾結(jié)。即便只是一個(gè)小小的 hello world,也需要加載幾乎所有的 API。Jigsaw 項(xiàng)目致力于把 Java 平臺(tái)和 JDK 分解成更小更有組織的模塊。用戶可以使用模塊來構(gòu)建軟件,并且不需要包含所有的 API。

這項(xiàng)工作并不容易,Oracle 的 Java 平臺(tái)組首席架構(gòu)師 Mark Reinhold 曾經(jīng)說過:

JDK代碼庫在API和實(shí)現(xiàn)級(jí)別上都是相互關(guān)聯(lián)的,多年來主要以單片軟件系統(tǒng)的方式構(gòu)建。我們花了相當(dāng)多的努力消除或至少簡化了盡可能多的API和實(shí)現(xiàn)依賴關(guān)系,以便平臺(tái)和它的實(shí)現(xiàn)可以作為一組相互依賴的模塊來呈現(xiàn),但是一些特別棘手的情況仍然存在。我們希望盡可能多地保持與先前版本的兼容性,特別是對(duì)于現(xiàn)有的基于類路徑的應(yīng)用程序,同時(shí)在可能的情況下,對(duì)于由模塊組成的應(yīng)用程序也是如此。

所有 Java 9 模塊都在 $JAVA_HOME/jmods 目錄下面。每個(gè)模塊都具有暴露給其他模塊的接口。這些模塊互相依賴,并通過導(dǎo)出的包進(jìn)行交互。 開發(fā)人員可以編譯、打包、部署和執(zhí)行僅由所選模塊組成的應(yīng)用程序,而無需其他任何操作。

如何使用模塊

下面我們把自己的 Java 代碼也進(jìn)行模塊化。新建兩個(gè)簡單的模塊:

  • com.timeteller.clock:包含SpeakingClock的模塊,用于將當(dāng)前時(shí)間打印到stdout的簡單類;
  • com.timeteller.main:使用com.timeteller.clock模塊提供的功能的模塊。

整個(gè)項(xiàng)目結(jié)構(gòu)如下所示:

├── com.timeteller.clock
│   ├── com
│   │   └── timeteller
│   │       └── clock
│   │           └── SpeakingClock.java
│   └── module-info.java
└── com.timeteller.main
    ├── com
    │   └── timeteller
    │       └── main
    │           └── Main.java
    └── module-info.java

在 main 函數(shù)中調(diào)用方法與之前并無多少不同。

public static void main (String[] args) {
    SpeakingClock clock = new SpeakingClock();
    clock.tellTheTime(); // displays the time to stdout.
}

Java 9 平臺(tái)級(jí)模塊化系統(tǒng)最重要的部分在 module-info.java 中,這個(gè)文件定義了模塊和元數(shù)據(jù)。內(nèi)容如下所示。一個(gè)文件定義了 com.timeteller.clock 模塊,并導(dǎo)出了 com.timeteller.clock 包;另一個(gè)文件定義了 com.timeteller.main 模塊,并引用了 com.timeteller.clock 模塊。

module com.timeteller.clock {
    exports com.timeteller.clock;
}
module com.timeteller.main {
    requires com.timeteller.clock;
}

module-info.java 的配置比較簡單,可以看到:

  • 模塊描述符文件放置在模塊的根文件夾中;
  • 每個(gè)模塊都有一個(gè)唯一的名稱;
  • 模塊描述符定義從模塊導(dǎo)出的包以及它們需要哪些模塊;

模塊中的包如果沒有導(dǎo)出,它的作用域就僅限于當(dāng)前模塊中,其他模塊無法使用。這一特性使得 Java 9 中的 public 含義有所變化,模塊中聲明為 public 的類不再是可以隨意訪問的,只有導(dǎo)出以后才能從模塊外訪問到?;谶@個(gè)特性,可以有效地隱藏模塊內(nèi)的 API。

編譯 Java 程序

編譯時(shí)可以這樣打包:

$ mkdir -p jars
$ mkdir -p build/classes/com.timeteller.clock
$ javac -d build/classes/com.timeteller.clock/ com.timeteller.clock/module-info.java com.timeteller.clock/com/timeteller/clock/SpeakingClock.java
$ jar -c -f jars/clock.jar -C build/classes/com.timeteller.clock/ .
$ mkdir -p build/classes/com.timeteller.main
$ javac -d build/classes/com.timeteller.main/ --module-path=jars com.timeteller.main/module-info.java com.timeteller.main/com/timeteller/main/Main.java
$ jar -c -f jars/timeTeller.jar --main-class com.timeteller.main.Main -C build/classes/com.timeteller.main .

我們必須告訴編譯器模塊的路徑(modulepath),編譯器才能準(zhǔn)確編譯。模塊路徑的概念與 classpath 的概念非常相似。當(dāng)我們構(gòu)建 com.timeteller.main 模塊時(shí),需要在它的模塊路徑上放一個(gè)帶有 com.timeteller.clock 的 jar。否則編譯器找不到必需的代碼并會(huì)導(dǎo)致編譯錯(cuò)誤:

$ javac -d build/classes/com.timeteller.main/ com.timeteller.main/module-info.java com.timeteller.main/com/timeteller/main/Main.java
com.timeteller.main/module-info.java:2: error: module not found: com.timeteller.clock
  requires com.timeteller.clock;

這里編譯后創(chuàng)建的 jar 也是模塊化,模塊的 jar 與常規(guī)的 jar 基本一樣,除了里面包括 module-info.class 文件。Java 9 即將到來,讓我們一起期待吧。

分享學(xué)習(xí)筆記和技術(shù)總結(jié),內(nèi)容涉及 Java 進(jìn)階、架構(gòu)設(shè)計(jì)、前沿技術(shù)、算法與數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)庫、中間件等多個(gè)領(lǐng)域。關(guān)注作者第一時(shí)間獲取最新內(nèi)容,公眾號(hào)同名(閱讀體驗(yàn)更佳)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容