Java 中的 JMOD 檔案格式
1. 概述
在本教程中,我們將深入探討 JMOD 的概念及其與 JAR 檔案的差異。然後,我們將創建一個範例模組化項目,將其打包成 JMOD 文件,並使用jlink產生一個專為該應用程式量身定制的最小 Java 運行時環境。
2. JMOD是什麼?
在 Java 9 之前,Java 應用程式主要以 JAR 檔案的形式打包,並使用 Maven 和 Gradle 等建置工具進行建置。隨著 Java 9 中 Java 平台模組系統 (JPS) 的引入,Java 獲得了正式的模組系統,並引入了 JMOD 檔案格式。
JMOD 檔案是 Java 模組的打包格式,這些模組旨在編譯和連結時使用,但不能直接在執行時使用。
與 JAR 檔案不同,執行應用程式時,我們不能將 JMOD 檔案放在類別路徑或模組路徑中。
與 JAR 檔案類似,JMOD 檔案可以包含已編譯的類別檔案和資源。但是,JMOD 檔案還可以包含其他內容,例如本機程式庫、設定檔和法律聲明。
2.1. 它與JPMS的關係
此外,JMOD 與 JPMS 密切相關。它是一種打包格式,用於打包那些可能需要除編譯後的字節碼檔案之外的其他內容的模組。
在JPMS架構中,原始碼被編譯成字節碼。然後,字節碼被打包成模組(JAR或JMOD)。最後,在連結時,我們可以使用jlink將這些模組組裝成自訂的運行時鏡像。
連結時是編譯和執行之間的階段。在此階段,Java 連結器會分析模組依賴關係,並將所需的模組打包到執行階段映像中。 JMOD 檔案專門用於參與連結過程。
2.2. JMOD 的用途及其與模組化 JAR 的區別
雖然 JPMS 支援模組化 JAR 文件,但 JMOD 的引入是為了解決 JAR 打包的限制。模組化 JAR 包含已編譯的類別和資源,可以直接在執行時使用。
另一方面,JMOD 檔案可能包含本地代碼和額外的元資料。它用於連結時處理,不能直接執行。與 JAR 檔案不同,它不應該發佈到 Maven Central 等程式碼倉庫。
它的主要目的是支援使用jlink創建自訂運行時鏡像。例如,將應用程式與完整的 JRE 打包在一起會顯著增加分發包的大小。而 JMOD 則允許建立僅包含應用程式所需模組的自訂 Java 執行時間。這樣可以減少分發包的大小,使其更方便學習者使用。
3. 實際範例:建立自訂 JRE
為了更好地理解 JMOD 檔案格式的工作原理,讓我們建立一個簡單的模組化 Java 應用程序,並使用它來創建自訂運行時映像。
3.1. 範例申請
讓我們啟動一個簡單的 Java 項目,該項目會在控制台輸出「 Hello Baeldung! 」:
public class Hello {
private static final Logger LOG = Logger.getLogger(Main.class.getName());
public static void main(String[] args) {
LOG.info("Hello Baeldung!");
}
}
在上面的程式碼中,我們定義了一個名為Hello類,並使用java.util.logging API 將一條訊息記錄到控制台。
接下來,讓我們透過在模組來源目錄的根目錄下加入module-info.java文件,將專案變成 Java 模組:
module com.baeldung.jmod_sample {
requires java.logging;
}
這裡, com.baeldung.jmod_sample是模組名稱。雖然每個模組都隱式依賴java.base ,但像java.logging這樣的其他模組必須明確聲明。
接下來,我們來編譯程式:
$ javac -d output $(find -name \*.java)
上述指令會找到src目錄下的所有.java檔並進行編譯。然後,它會將產生的.class檔案輸出到output目錄。
3.2. 打包到 JMOD
接下來,讓我們將模組化應用程式打包成 JMOD 文件,以便建立自訂執行時間。
要建立 JMOD 文件,我們可以使用jmod create指令:
$ jmod create \
--class-path output/ \
--main-class com.baeldung.jmod_sample.Hello \
--module-version 1.0.0 -p output hello.jmod
這裡, –class-path output/指定了包含已編譯類別的目錄。此外,我們也定義了模組的入口點和產生的 JMOD 檔案的名稱。
執行該指令後,將在目前目錄中建立一個hello.jmod檔。
接下來,我們執行jmod describe指令來檢查 JMOD 文件,看看它包含什麼內容:
$ jmod describe hello.jmod
這會將文件內容輸出到控制台:
[email protected]
requires java.base mandated
requires java.logging
contains com.baeldung.jmod_sample
main-class com.baeldung.jmod_sample.Hello
這證實了 JMOD 檔案正確地封裝了編譯模組及其元數據,使其可以在連結時使用jlink進行編譯。
3.3. 使用jlink建立自訂運行時
現在我們已經產生了 JMOD 文件,讓我們使用它透過jlink建立一個自訂 Java 執行時間環境:
$ jlink \
--module-path $JAVA_HOME/jmods:hello.jmod \
--add-modules com.baeldung.jmod_sample \
--launcher hello=com.baeldung.jmod_sample/com.baeldung.jmod_sample.Hello \
--strip-debug \
--compress=2 \
--no-header-files \
--no-man-pages \
--output custom-runtime-min
這裡, –module-path $JAVA_HOME/jmods:hello.jmod指定了 jlink 應該在哪裡找到所需的模組。接下來,` –add-modules選項指定了要包含在執行時間映像中的根模組。
然後我們使用launcher選項來建立一個運行Hello類別的啟動腳本。執行指令後, jlink會產生一個名為「 custom-runtme-min 」的新目錄。
我們可以檢查產生的運行時映像的大小:
$ du -sh custom-runtime-min
以下是輸出結果:
35M custom-runtime-min/
產生的執行時間環境大小約為 35 MB,遠小於完整的 JDK 安裝套件(通常超過 400 MB)。
讓我們來驗證運行時鏡像包含了哪些模組:
$ ./custom-runtime-min/bin/java --list-modules
以下是輸出結果:
[email protected]
[email protected]
[email protected]
這證實了只包含了所需的模組。
最後,我們運行生成啟動器:
$ ./custom-runtime-min/bin/hello
上述命令的輸出結果為:
Mar 01, 2026 10:15:38 AM com.baeldung.jmod_sample.Hello main
INFO: Hello Baeldung!
使用自訂運行時映像,應用程式運行成功。
4. 結論
本文介紹了 JMOD 檔案是什麼、它可以包含哪些內容、它與 JAR 檔案的差異以及何時應該使用它。此外,我們還建立了一個簡單的模組化 Java 應用程序,將其打包成 JMOD 文件,並使用jlink生成了一個精簡的、自訂的 Java 運行時映像,該映像專門針對我們的應用程式量身定制。
與往常一樣,該範例的完整原始程式碼可在 GitHub 上找到。