2021年12月12日 星期日

2. 建立和執行模組化程式

在本節中,我們將建立、構建和執行zoo.animal.feeding模組。我們選擇這個作為開始是因為所有其他模組都相依於它。 下圖顯示了該模組的設計。除了module-info.java檔案外,它還有1個套件,裡面有1個類別:
後續將建立、編譯、執行和打包zoo.animal.feeding模組。

建立模組專案

建立套件、類別與模組資訊檔案

首先建立專案zoo.animal.feeding與套件zoo.animal.feeding,本例專案名稱與套件名稱相同;然後建立簡單的類別Task.java,內容如下:

package zoo.animal.feeding;
public class Task {
    public static void main(String... args) {
        System.out.println("All are fed!");
    }
}

接下來是建立模組資訊(module info)檔案。模組資訊檔案和一般Java類別之間有一些主要區別:

  1. module-info檔案必須位於模組的根目錄中,一般Java類別應該在套件中。
  2. module-info檔案內容宣告模組時使用關鍵字module而不是class、interface或enum。
  3. 模組檔案名稱遵循套件名稱的命名規則,它的名稱中通常包含「.」。一般類別和套件名稱不允許有「-」,但模組可以。
後續還會說明更多模組資訊檔案的內容規則,就一個最簡單的模組資訊檔案內容如下:
module zoo.animal.feeding {
}

此外,我們在與src目錄的同一檔案階層建立了一個名為mods的目錄,我們將在本章稍後部分使用它來存放與自身模組相依的其他模組。這個目錄可以任意命名,但mods是一個比較通用名稱。完成後專案目錄結構如下:

專案結構的src目錄是模組目錄,模組資訊檔案就在它根目錄。我們也有zoo.animal.feeding套件,以作業系統的角度來看每一層套件就表示一個子目錄,可以由Eclipse的Project Explorer和Navigator比較。Task類別位於其套件的相應子目錄中。

使用Eclipse建立的專案預設會將*.java檔案自動編譯為*.class檔案,並存放在專案內的bin目錄中。不過我們只是使用Eclipse協助建立專案,後續編譯將以指令進行。

編譯模組專案

在可以執行模組化程式碼之前,需要先予以編譯,指令如下。為了說明指令列選項讓讀者容易理解,因此拆解成4行,實際執行時必須合併為1行,或是使用作業系統的斷行符號,如Linux使用「\」:

javac 
--module-path mods
-d src 
src/zoo/animal/feeding/*.java src/module-info.java

說明:

2

使用選項「--module-path」指示任何自定義模組檔案的位置,本例是mods目錄。由於mods目前沒有任何相依模組檔案,因此可以忽略本選項。此外選項「--module-path」和大家熟悉的選項「-classpath」相似,當處理模組化程式時,可以將「--module-path」視為替換「-classpath」選項。

3

使用選項「-d」指定放置編譯完成的類別檔案的目錄。

4

指令的結尾是要編譯的Java檔案清單。可以單獨列出這些檔案,也可以對子目錄中的所有Java檔案使用萬用字元「*.java」。使用空白(space)區隔清單內容。

就像類別路徑一樣,我們可以在指令列中使用縮寫。選項「--module-path」和「-p」是等效的,因此前述指令列可以修改如下

javac -p mods -d src src/zoo/animal/feeding/*.java src/module-info.java

以本例而言,執行指令時必須在src資料夾。要找出src目錄的路徑可以在src目錄的節點上以滑鼠右鍵點擊,選擇Properties

彈出「Properties for src」視窗後點擊以下Location圖式:

在彈出的檔案總管視窗的資料夾路徑處,改鍵入「cmd」文字並點擊鍵盤Enter鍵:

彈出系統管理員視窗,且目前路徑即為專案的src目錄:

鍵入編譯模組的指令並Enter:

範例專案每一個的*.java將伴隨著*.class檔案:

在一開始學習Java時理解java與javac指令是必要的。但實際在開發專案時,如果繼續組裝指令列會發現它們變得冗長而復雜。我們使用Eclipse開發時,編譯和執行都由IDE代勞;若要結合DevOps的開發流程,大多數開發人員會使用自動化構建工具,例如Maven或Gradle。讀者若對這些進階內容有興趣,可以參考「Spring Boot情境式網站開發指南:使用Spring Data JPA、Spring Security、Spring Web Flow」一書的「CH1. 使用Maven管理Java專案」。

執行模組專案

在打包模組之前,我們應該先確認該模組是否可以正確執行。為此我們需要了解完整的語法。假設有一個名為lab.module的模組,該模組中具備org.some的套件,和帶有一個main()方法的Test的類別。下圖顯示了執行模組的語法,特別注意lab.module/org.some.Test部分。請務必記住指定的模組名稱後跟著「/」,之後才是完整的類別名稱。

現在我們已經理解了語法,可以編寫指令來執行zoo.animal.feeding套件中的Task類別。在以下指令中,套件名稱和模組名稱相同,都是zoo.animal.feeding。模組名稱經常會與套件的完整名稱相同,或是取套件開頭的幾個名稱空間(namespace),如zoo.animal。
java 
--module-path src 
--module zoo.animal.feeding/zoo.animal.feeding.Task
說明

2

使用「--module-path」選項指定模組路徑,也可以使用「-p」。

3

使用「--module」指定執行對象,也可以使用「-m」。

執行對象以「/」區隔。之前為模組名稱,之後為完整的套件和類別名稱。

在本範例中行2使用src作為模組路徑,是因為這是本專案、同時也是前一個範例編譯後產出*.class的地方。後續範例打包模組成為JAR檔案時,執行時就會改指定JAR檔案位置。

執行「java -p src -m zoo.animal.feeding/zoo.animal.feeding.Task」後可以得到視窗輸出「All are fed!」字樣:


打包模組專案

如果我們只能在建立模組的路徑如src目錄中執行它,那程式模組化的用處就不大。我們的下一步是打包它,讓模組可以在其他地方執行,或是給其他模組使用。指令如下:

jar  
-cvf mods/zoo.animal.feeding.jar 
-C src/ .
說明

2

使用「-cvf」選項指定要打包為JAR檔案。

本例中「mods」是JAR檔案的產出目錄,要事先建立。「zoo.animal.feeding.jar」是JAR檔案名稱。

3

使用「-C」指定編譯好的*.class檔案位置。

本例中「src/ .」表示路徑src內的所有檔案。

事實上該指令不只可以打包Java的模組化程式為一個JAR檔案,即便「非模組化」程式也是相同的打包指令。打包完成後該Java程式就可以給其他專案使用!

以指令「jar -cvf mods/zoo.animal.feeding.jar -C src/ .」進行打包:

更新(refresh)專案後,可以看到mods目錄出現zoo.animal.feeding.jar檔案:

現在讓我們以打包後的模組化JAR檔案執行程式:

java 
--module-path mods 
--module zoo.animal.feeding/zoo.animal.feeding.Task
注意行2指定的模組路徑是mods而不是src,目錄mods已經存在打包好的「zoo.animal.feeding.jar」,目錄src存放編譯好的鬆散*.class檔案。

執行「java -p mods -m zoo.animal.feeding/zoo.animal.feeding.Task」後可以得到視窗輸出「All are fed!」字樣:




沒有留言:

張貼留言