Java?JAR文件的打包與運(yùn)行過(guò)程
在 Java 開(kāi)發(fā)中,JAR(Java Archive)文件是一種核心的分發(fā)格式,用于將多個(gè)類文件、元數(shù)據(jù)和資源打包成一個(gè)壓縮文件。JAR 文件不僅便于應(yīng)用程序的部署,還可以通過(guò)配置清單文件(manifest)使其成為可執(zhí)行文件。本文將深入探討如何使用 JDK 的 jar
工具手動(dòng)創(chuàng)建 JAR 文件,以及如何利用 Maven 自動(dòng)化這一過(guò)程。我們將通過(guò)清晰的示例和步驟,確保內(nèi)容深入淺出,為技術(shù)人員提供實(shí)用的指導(dǎo)。
本文的目標(biāo)是幫助您:
- 理解 JAR 文件的作用和結(jié)構(gòu)。
- 掌握使用
jar
工具創(chuàng)建可執(zhí)行 JAR 文件的方法。 - 學(xué)習(xí)如何配置 Maven 以生成包含依賴的 JAR 文件。
- 了解高級(jí)工具(如
jpackage
)的潛在用途。
什么是 JAR 文件?
JAR 文件是基于 ZIP 和 ZLIB 壓縮格式的歸檔文件,主要用于打包 Java 應(yīng)用程序或庫(kù)的組件,包括:
- 類文件:編譯后的
.class
文件,包含 Java 程序的字節(jié)碼。 - 資源文件:如圖片、配置文件或音頻文件。
- 清單文件:位于
META-INF/MANIFEST.MF
,包含文件的元數(shù)據(jù)和屬性。
JAR 文件的主要優(yōu)勢(shì)包括:
- 高效分發(fā):將所有相關(guān)文件打包為單一文件,便于傳輸。
- 壓縮:減少文件大小,加快下載速度。
- 可執(zhí)行性:通過(guò)指定
Main-Class
屬性,JAR 文件可以直接運(yùn)行。 - 模塊化:自 JDK 9 起,JAR 文件支持模塊化打包(模塊化 JAR)。
使用 jar 命令創(chuàng)建 JAR 文件
JDK 提供的 jar
工具是創(chuàng)建和操作 JAR 文件的標(biāo)準(zhǔn)工具。以下是通過(guò)命令行創(chuàng)建可執(zhí)行 JAR 文件的步驟。
步驟 1:編寫(xiě)并編譯 Java 代碼
假設(shè)我們有一個(gè)簡(jiǎn)單的 Java 程序 HelloWorld.java
,位于 com.somedomainhere
包中:
package com.somedomainhere; public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World of Java"); } }
在命令行中,編譯該文件:
javac com/somedomainhere/HelloWorld.java
這將在 com/somedomainhere
目錄下生成 HelloWorld.class
文件。
步驟 2:創(chuàng)建清單文件
要使 JAR 文件可執(zhí)行,需要一個(gè)清單文件來(lái)指定主類。創(chuàng)建一個(gè)名為 manifest.stub
的文本文件,內(nèi)容如下:
Main-Class: com.somedomainhere.HelloWorld
注意:
Main-Class
屬性區(qū)分大小寫(xiě),且冒號(hào)后必須有一個(gè)空格。- 文件必須以換行符結(jié)尾,否則可能導(dǎo)致解析錯(cuò)誤。
步驟 3:創(chuàng)建 JAR 文件
假設(shè)當(dāng)前目錄結(jié)構(gòu)如下:
. └── com └── somedomainhere └── HelloWorld.class
在包含 com
目錄的根目錄下,運(yùn)行以下命令:
jar cvmf manifest.stub hello.jar com/somedomainhere/HelloWorld.class
命令參數(shù)說(shuō)明:
c
:創(chuàng)建新的歸檔文件。v
:顯示詳細(xì)輸出(verbose)。m
:包含指定的清單文件(manifest.stub
)。f
:指定輸出文件名(hello.jar
)。
執(zhí)行后,將生成 hello.jar
,其中包含正確的包結(jié)構(gòu)(com/somedomainhere/HelloWorld.class
)和清單文件。
步驟 4:驗(yàn)證 JAR 文件內(nèi)容
您可以使用以下命令查看 JAR 文件的內(nèi)容:
jar tf hello.jar
輸出示例:
META-INF/
META-INF/MANIFEST.MF
com/
com/somedomainhere/
com/somedomainhere/HelloWorld.class
運(yùn)行 JAR 文件
創(chuàng)建 JAR 文件后,可以通過(guò)以下命令運(yùn)行:
java -jar hello.jar
java -jar
命令會(huì)讀取清單文件中的 Main-Class
屬性,并執(zhí)行指定的主類。運(yùn)行上述命令將輸出:
Hello, World of Java
在支持的 GUI 平臺(tái)(如 Windows、macOS 或某些 Linux 桌面環(huán)境)上,您可以雙擊 JAR 文件運(yùn)行,前提是系統(tǒng)已將 .jar
文件關(guān)聯(lián)到 Java 運(yùn)行時(shí)環(huán)境(JRE)。
注意:
- 確保已安裝 Java 運(yùn)行時(shí)環(huán)境(JRE)或 JDK。
- 如果 JAR 文件缺少
Main-Class
屬性或主類不存在,將拋出異常。
使用 Maven 創(chuàng)建 JAR 文件
對(duì)于大型項(xiàng)目,手動(dòng)創(chuàng)建 JAR 文件可能效率低下。Maven 是一種流行的構(gòu)建工具,可以自動(dòng)化編譯、打包和依賴管理。以下是如何使用 Maven 創(chuàng)建可執(zhí)行 JAR 文件的步驟。
步驟 1:設(shè)置 Maven 項(xiàng)目
創(chuàng)建一個(gè)標(biāo)準(zhǔn)的 Maven 項(xiàng)目,目錄結(jié)構(gòu)如下:
hello-world/ ├── pom.xml └── src └── main └── java └── com └── somedomainhere └── HelloWorld.java
HelloWorld.java
的內(nèi)容與之前相同。
步驟 2:配置 pom.xml
在 pom.xml
中,指定項(xiàng)目的基本信息和插件配置。以下是一個(gè)基本的配置,用于生成可執(zhí)行 JAR 文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.somedomainhere</groupId> <artifactId>hello-world</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.0</version> <configuration> <archive> <manifest> <mainClass>com.somedomainhere.HelloWorld</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build> </project>
說(shuō)明:
<packaging>jar</packaging>
:指定項(xiàng)目打包為 JAR 文件。maven-compiler-plugin
:設(shè)置 Java 編譯版本(這里使用 Java 8)。maven-jar-plugin
:配置清單文件,指定主類。
運(yùn)行以下命令生成 JAR 文件:
mvn clean package
這將在 target
目錄下生成 hello-world-1.0-SNAPSHOT.jar
。您可以運(yùn)行:
java -jar target/hello-world-1.0-SNAPSHOT.jar
步驟 3:包含依賴項(xiàng)(創(chuàng)建胖 JAR)
如果您的項(xiàng)目有外部依賴(如第三方庫(kù)),上述 JAR 文件不包含這些依賴,運(yùn)行時(shí)可能拋出 ClassNotFoundException
。要?jiǎng)?chuàng)建包含所有依賴的“胖 JAR”,可以使用 maven-assembly-plugin
。
在 pom.xml
中添加以下插件配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.3.0</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.somedomainhere.HelloWorld</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
運(yùn)行以下命令:
mvn clean package
這將生成兩個(gè) JAR 文件:
target/hello-world-1.0-SNAPSHOT.jar
:不包含依賴的普通 JAR。target/hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar
:包含所有依賴的胖 JAR。
運(yùn)行胖 JAR:
java -jar target/hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar
優(yōu)點(diǎn):
- 胖 JAR 是自包含的,可以在任何安裝了 Java 的環(huán)境中運(yùn)行,無(wú)需額外配置類路徑。
- 便于分發(fā),適合獨(dú)立應(yīng)用程序。
注意:
- 胖 JAR 可能顯著增加文件大小,因?yàn)樗幸蕾嚒?/li>
- 確保依賴的許可證允許這種打包方式。
示例:添加依賴
假設(shè)您的程序使用 Apache Commons Lang 庫(kù)。更新 pom.xml
添加依賴:
<dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> </dependencies>
修改 HelloWorld.java
使用該庫(kù):
package com.somedomainhere; import org.apache.commons.lang3.StringUtils; public class HelloWorld { public static void main(String[] args) { String message = "hello, world of java"; System.out.println(StringUtils.capitalize(message)); } }
重新運(yùn)行 mvn clean package
,生成的胖 JAR 將包含 Commons Lang 庫(kù),運(yùn)行時(shí)將輸出:
Hello, world of java
高級(jí)主題
使用 Maven Shade 插件
雖然 maven-assembly-plugin
適用于大多數(shù)場(chǎng)景,但 maven-shade-plugin
提供了更高級(jí)的功能,如包重命名(shading)以避免類沖突。配置示例:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.somedomainhere.HelloWorld</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
運(yùn)行 mvn clean package
將生成包含所有依賴的 JAR 文件。Shade 插件特別適合需要處理復(fù)雜依賴沖突的項(xiàng)目。
使用 jpackage 工具
自 Java 14 起,JDK 引入了 jpackage
工具,可創(chuàng)建平臺(tái)特定的安裝程序(如 Windows 的 .exe
或 macOS 的 .dmg
)。它將應(yīng)用程序和 JRE 打包在一起,適合分發(fā)給非技術(shù)用戶。
示例命令:
jpackage --input target --name HelloWorld --main-jar hello-world-1.0-SNAPSHOT.jar --main-class com.somedomainhere.HelloWorld
由于 jpackage
超出了 JAR 文件的范圍,建議有興趣的讀者參考 Oracle 文檔。
常見(jiàn)問(wèn)題與注意事項(xiàng)
問(wèn)題 | 解決方案 |
---|---|
java -jar 拋出 no main manifest attribute | 確保清單文件中包含 Main-Class 屬性,或在 jar 命令中使用 -e 選項(xiàng)指定主類。 |
運(yùn)行胖 JAR 時(shí)出現(xiàn) ClassNotFoundException | 確認(rèn) maven-assembly-plugin 已正確配置,且所有依賴都包含在 JAR 中。 |
JAR 文件過(guò)大 | 考慮使用普通 JAR 并通過(guò)類路徑管理依賴,或檢查是否有不必要的依賴。 |
雙擊 JAR 文件無(wú)法運(yùn)行 | 確保系統(tǒng)安裝了 JRE,并將 .jar 文件關(guān)聯(lián)到 javaw.exe。 |
總結(jié)
打包和運(yùn)行 JAR 文件是 Java 開(kāi)發(fā)中的核心技能。通過(guò) jar
工具,您可以手動(dòng)創(chuàng)建簡(jiǎn)單的 JAR 文件,適合小型項(xiàng)目或?qū)W習(xí)目的。而 Maven 提供了強(qiáng)大的自動(dòng)化功能,能夠處理復(fù)雜的依賴管理和構(gòu)建流程,使其成為現(xiàn)代 Java 開(kāi)發(fā)的首選工具。本文通過(guò)詳細(xì)的示例和配置,展示了從基礎(chǔ)到高級(jí)的 JAR 文件管理方法。
無(wú)論您是初學(xué)者還是經(jīng)驗(yàn)豐富的開(kāi)發(fā)者,掌握這些技術(shù)將顯著提高您的開(kāi)發(fā)效率。建議進(jìn)一步探索 Maven 的其他插件(如 maven-shade-plugin
)或 jpackage
工具,以滿足更復(fù)雜的部署需求。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java class文件格式之屬性詳解_動(dòng)力節(jié)點(diǎn)java學(xué)院整理
這篇文章主要介紹了Java class文件格式之屬性詳解,需要的朋友可以參考下2017-06-06詳解使用spring boot admin監(jiān)控spring cloud應(yīng)用程序
本篇文章主要介紹了詳解使用spring boot admin監(jiān)控spring cloud應(yīng)用程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11Spring Bean創(chuàng)建和循環(huán)依賴
這篇文章主要介紹了Spring Bean創(chuàng)建和循環(huán)依賴,講述了Spring容器中?Bean?的創(chuàng)建過(guò)程已經(jīng)主要的方法,另外也著重分析了循環(huán)依賴的問(wèn)題,需要的小伙伴可以參考一下2022-05-05關(guān)于Java中修飾符的總結(jié)(fina除外)
下面小編就為大家?guī)?lái)一篇關(guān)于Java中修飾符的總結(jié)(fina除外)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09Java Cache詳解及簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要介紹了 Java Cache詳解及簡(jiǎn)單實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-02-02Java基于Lock的生產(chǎn)者消費(fèi)者模型示例
這篇文章主要介紹了Java基于Lock的生產(chǎn)者消費(fèi)者模型,結(jié)合實(shí)例形式分析了java基于鎖機(jī)制的生產(chǎn)者消費(fèi)者模型相關(guān)實(shí)現(xiàn)與使用技巧,需要的朋友可以參考下2018-08-08關(guān)于spring 掃描不到j(luò)ar中class文件的原因分析及解決
這篇文章主要介紹了關(guān)于spring 掃描不到j(luò)ar中class文件的原因分析及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08