META-INF/MANIFEST.MF 清單文件定義入口點、版本、依賴、簽名、模塊化信息java -jar app.jar 一條命令運行jar 工具
# 編譯源碼
javac -d out src/com/example/Hello.java
# 創建可運行 JAR (c=create, v=verbose, f=file, m=manifest)
# 方式一:指定主類
jar cvfe app.jar com.example.Hello -C out .
# 方式二:使用預寫清單
echo "Main-Class: com.example.Hello" > manifest.txt
jar cvfm app.jar manifest.txt -C out .
# 方式三:模塊化 JAR (JDK 9+)
jar cvfe app.jar com.example.Hello --module-version 1.0 -C out .
jar tf app.jar # 列出文件
jar tvf app.jar # 詳細信息 (大小、時間、壓縮率)
jar xf app.jar # 解壓全部
jar xf app.jar com/example/Hello.class # 解壓單個文件
jar uvf app.jar com/example/Hello.class # 更新/添加文件
jar uvfm app.jar manifest.txt # 更新清單屬性
Manifest-Version: 1.0
Created-By: 17.0.2 (Oracle Corporation)
Main-Class: com.example.Hello # 入口類
Class-Path: lib/dep1.jar lib/dep2.jar # 依賴路徑 (相對路徑、空格分隔、不支持通配符)
Sealed: true # 密封包 (防止包分散在多 JAR)
Implementation-Title: MyApp
Implementation-Version: 1.0.0
Implementation-Vendor: MyCompany
Specification-Title: MyAPI
Specification-Version: 1.0
Multi-Release: true # 多版本 JAR (JDK 9+)
Automatic-Module-Name: com.example.app # 自動模塊名 (JDK 9+ 非模塊化 JAR)
Name: com/example/api/
Sealed: true
Specification-Version: 1.0
Implementation-Version: 1.0.0
| 陷阱 | 現象 | 根因 | 解決 |
|---|---|---|---|
| 無 Main-Class | no main manifest attribute | 清單缺少入口點 | jar cvfe 或清單指定 Main-Class |
| 依賴 JAR 未加載 | NoClassDefFoundError | Class-Path 不生效 (絕對路徑、JAR 嵌套、空格轉義) | 1. Maven Shade Plugin 打包 Fat JAR 2. Spring Boot Loader 類加載器 3. 自定義 ClassLoader 掃描 lib/ 目錄 |
| 雙擊無反應/彈出壓縮軟件 | Windows 關聯錯誤 | .jar 關聯到壓縮軟件而非 javaw.exe | 控制面板→默認程序→關聯 .jar 到 javaw.exe -jar "%1" %* |
# 生成密鑰庫
keytool -genkeypair -alias mykey -keystore my.keystore -storepass 123456 -keypass 123456
# 簽名
jarsigner -keystore my.keystore -storepass 123456 -signedjar app-signed.jar app.jar mykey
# 驗證
jarsigner -verify -verbose -certs app-signed.jar
# 運行時驗證策略
java -Djava.security.manager -Djava.security.policy=policy.all -jar app-signed.jar
簽名機制:對每個條目計算 SHA-256 摘要,存入 MANIFEST.MF,再對清單簽名生成 .SF、.DSA/.RSA/.EC 文件。運行時驗證完整性與發布者身份。
jar cvfe mr.jar com.example.Main --release 8 -C out8 . --release 11 -C out11 . --release 17 -C out17 .
META-INF/versions/8/, META-INF/versions/11/, META-INF/versions/17/
# module-info.java
module com.example.app {
requires java.sql;
requires org.slf4j;
exports com.example.api;
uses com.example.spi.Service;
provides com.example.spi.Service with com.example.impl.ServiceImpl;
}
# 編譯
javac -d out --module-source-path src $(find src -name "*.java")
# 打包模塊化 JAR
jar cvfe app.jar com.example.Main --module-version 1.0 -C out .
module-info.class 置於 JAR 根目錄-p) 替代類路徑 (-cp),可靠構建、啟動更快
org.apache.maven.plugins
maven-shade-plugin
3.4.1
package
shade
com.example.Main
META-INF/spring.factories
true
org.springframework.boot
spring-boot-maven-plugin
com.example.Application
true
repackage
特性:嵌入式容器、自定義類加載器 (加載 BOOT-INF/lib/)、Profile 配置、Actuator 端點、Docker 原生構建 (spring-boot:build-image)。
| 時代 | 產物 | 特點 | 工具 |
|---|---|---|---|
| JDK 1-8 | Fat JAR / WAR | 類路徑地獄、版本衝突、啟動慢 | Maven Shade, Spring Boot Loader |
| JDK 9+ | 模塊化 JAR / Multi-Release JAR | 強封裝、可靠構建、版本共存 | JPMS, JLink, JPackage |
| GraalVM | Native Image | 毫秒啟動、無 JIT 預熱、體積小、無需 JRE | native-image, Spring AOT, Micronaut, Quarkus |
| 雲原生 | OCI Image (Docker) | 層級緩存、不可變基礎設施、K8s 原生 | Spring Boot 3.1+ Buildpacks, Jib, Dockerfile |
JAR 是 Java 生態的基礎貨幣。掌握 jar 命令行、清單屬性、簽名驗證、多版本/模塊化特性,配合 Maven/Gradle 插件最佳實踐,能構建出可運行、可驗證、可演進、生產就緒的分發產物。現代項目請直接擁抱 Spring Boot Fat JAR / 模塊化 JAR / GraalVM Native Image / Docker 鏡像 四大分發形態,告別手工拼裝與類路徑地獄。