使用jlink工具模塊化Java應用,結合Docker優化容器鏡像(上)
使用jlink工具模塊化Java應用,結合Docker優化容器鏡像(中)
依賴統一管理
當項目中的依賴越來越多時,對模塊的管理會越發的複雜,容易出錯。這裏使用maven-dependency-plugin插件對依賴做統一的管理,減少工作量,避免不必要的模塊管理工作。注意:這個插件需要放在第一個插件的位置,避免將其它插件生成的依賴包覆蓋掉。
- 使用maven-dependency-plugin,將項目所有的依賴放在同一個目錄,實現模塊的目錄路徑統一。通過指定outputDirectory,將項目用到的所有依賴都複製到該目錄下面。
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/modules
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
- 在modulePath中使用<path>${project.build.directory}/modules</path>,將該目錄下的所有依賴包都作爲模塊導入項目。因爲項目自身的模塊不在該目錄下,所以要單獨導入,即第一個<path>節點。
<configuration>
<modulePath>
<path>
${project.build.directory}/${project.artifactId}-${project.version}.${project.packaging}
</path>
<path>
${project.build.directory}/modules
</path> <!-- 添加的代碼 -->
</modulePath>
</configuration>
添加自身是模塊的依賴
接下來改進程序和代碼。你們可能知道,在代碼中直接使用System.out.println()是不明智的,因爲它們無法被配置,因此它們只能達到調試的目的,並且即使發佈產品時,它們依然會輸出到控制檯。讓我們使用一個適當的日誌框架來代替這個日誌聲明。
我將使用已經被模塊化的slf4j日誌框架[https://www.slf4j.org/]。這個選擇需要添加兩個依賴:API(slf4j-api)和單一實現(slf4j-simple)模塊。
在POM文件中添加如下依賴:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.8.0-beta2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.8.0-beta2</version>
</dependency>
更新項目的module-info.java:
module ch.frankel.jlink {
requires org.slf4j.simple;
requires org.slf4j;
exports ch.frankel.blog.jlink;
}
這裏使用的依賴都是被模塊化的,即依賴包的根目錄下是自帶module-info.java文件的。如果我們引入的是一個未被模塊化的依賴包該怎麼辦呢?
添加非模塊化的依賴
這裏我們已javax.jms-1.1消息服務依賴爲例,這個1.1版本肯定是不具備模塊化的,但是在jlink中是不允許使用非模塊化的依賴的,所以JDK中提供了一個jdeps工具對非模塊化的依賴處理成模塊化的。但是我們可以繼續通過moditect-maven-plugin插件簡單並統一的添加非模塊化依賴,代碼如下:
- 添加jms-1.1依賴:
<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
</dependency>
- 在moditect-maven-plugin插件節點中添加add-module-info執行節點,對指定的非模塊化依賴包創建並添加module-info.class文件,生成新的依賴包,從而實現對該依賴包的模塊化。注意:需要將生成的依賴包路徑指向指定的路徑,並設置可對包文件進行覆蓋寫入。如果需要添加多個非模塊化依賴,在<modules>節點中按格式添加多個<module>節點即可。
<execution>
<id>add-module-info</id>
<phase>package</phase>
<goals>
<goal>add-module-info</goal>
</goals>
<configuration>
<modules>
<module>
<artifact>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
</artifact>
<moduleInfo>
<name>jms</name>
</moduleInfo>
</module>
</modules>
<outputDirectory>
${project.build.directory}/modules
</outputDirectory>
<overwriteExistingFiles>true</overwriteExistingFiles>
</configuration>
</execution>
至此,你已經完全掌握了對jlink這個工具的使用姿勢。一個項目經過jlink工具的模塊化,就能實現在未安裝JDK9或更高版本的計算機上運行你的Java應用了,因爲我們生成的是一個可單獨運行的鏡像。當然你還可以通過編寫一個vbs文件再使用AutoIt3這個工具,生成一個exe執行文件,具體使用視項目情況而定。