首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JAR 文件揭密:探索 JAR 文件格式的強大功能

     編輯:Java 相關知識

什麼是 JAR 文件?

JAR 文件格式以流行的 ZIP 文件格式為基礎,用於將許多文件聚集為一個文件。與 ZIP 文件不同,JAR 文件不僅用於壓縮和發布,還用於部署和封裝庫、組件和插件程序,並可被編譯器和 JVM 等工具直接使用。JAR 中包含特殊文件,如 manifests 和部署描述符,用來指示工具如何處理特定 JAR。

一個 JAR 文件可用於:

  • 發布和使用類庫
  • 作為應用程序和擴展的構建單元
  • 作為組件、applet 或插件程序的部署單位
  • 打包與組件相關聯的輔助資源

JAR 格式提供許多優勢和功能,許多是傳統壓縮格式如 ZIP 或 TAR 所無:

  • 安全性:可對 JAR 內容加數字簽名,識別簽名工具可選擇授予軟體安全特權,還可檢測代碼是否被篡改。
  • 減少下載時間:applet 捆綁在 JAR 中,瀏覽器可在一個 HTTP 事務中下載 applet 類文件和相關資源,而非對每個文件打開新連接。
  • 壓縮:JAR 格式允許壓縮文件以提高存儲效率。
  • 傳輸平台擴展:Java 擴展框架提供向 Java 核心平台添加功能方法,擴展用 JAR 打包(如 Java 3D、JavaMail)。
  • 包密封:JAR 中的包可選擇密封,增強版本一致性和安全性。密封意味著包中所有類必須在同一 JAR 中找到。
  • 包版本控制:JAR 可包含所含文件數據,如廠商和版本信息。
  • 可移植性:處理 JAR 文件機制是 Java 平台核心 API 標準部分。

壓縮與未壓縮 JAR

jar 工具預設壓縮文件。未壓縮 JAR 一般比壓縮 JAR 載入更快(載入過程中需解壓縮),但未壓縮文件網絡下載時間可能更長。

META-INF 目錄

大多數 JAR 包含 META-INF 目錄,存儲包和擴展配置數據,如安全性和版本信息。Java 2 平台識別並解釋其中文件和目錄,以配置應用、擴展和類加載器:

  • MANIFEST.MF:定義與擴展和包相關數據。
  • INDEX.LIST:由 jar -i 生成,包含應用或擴展中定義包的位置信息,是 JarIndex 實現一部分,由類加載器用於加速類加載。
  • xxx.SF:JAR 簽名文件,xxx 標識簽名者。
  • xxx.DSA:與簽名文件相關聯的簽名程序塊文件,存儲用於簽名 JAR 的公共簽名。

jar 工具

執行基本任務用 Java Archive Tool(jar 工具),作為 JDK 一部分提供。用 jar 命令調用。常見用法:

功能命令
用單個文件創建 JARjar cf jar-file input-file...
用目錄創建 JARjar cf jar-file dir-name
創建未壓縮 JARjar cf0 jar-file dir-name
更新 JARjar uf jar-file input-file...
查看 JAR 內容jar tf jar-file
提取 JAR 內容jar xf jar-file
提取特定文件jar xf jar-file archived-file...
運行可執行 JAR 應用java -jar app.jar

可執行 JAR

可執行 JAR 是自包含 Java 應用,存儲在特別配置的 JAR 中,可由 JVM 直接執行無需提取文件或設置類路徑。運行非可執行 JAR 中應用,必須加入類路徑並用名字調用主類。但用可執行 JAR,無需提取或知道主要入口點即可運行應用,有助於方便發布和執行。

創建可執行 JAR

將所有應用代碼放到一目錄。假設主類為 com.mycompany.myapp.Sample。創建包含應用代碼的 JAR 並標識主類:在某位置(非應用目錄)創建 manifest 文件,加入:

Main-Class: com.mycompany.myapp.Sample

然後創建 JAR:

jar cmf manifest ExecutableJar.jar application-dir

現在可用 java -jar ExecutableJar.jar 執行。可執行 JAR 必須通過 manifest 文件頭引用所需所有從屬 JAR。若使用 -jar 選項,環境變量 CLASSPATH 和命令行指定類路徑都被 JVM 忽略。

啟動可執行 JAR

java -jar ExecutableJar.jar

包密封

密封 JAR 中包意味著包中定義所有類必須在同一 JAR 中找到,增強版本一致性,提供防止代碼篡改手段。要密封包,在 JAR manifest 為包添加 Name 頭,再加值為 "true" 的 Sealed 頭。創建 JAR 時指定具有適當頭元素的 manifest 文件密封 JAR:

Name: com/samplePackage/
Sealed: true

Name 頭標識包相對路徑名,以 "/" 結束以與文件名區別。Name 頭後第一個空行前所有頭作用於 Name 頭指定文件或包。上例中 Sealed 頭出現在 Name 後且中間無空行,故只應用於 com/samplePackage 包。若嘗試從密封包所在 JAR 以外其他地方加載密封包中類,JVM 將拋出 SecurityException。

擴展打包

擴展為 Java 平台增加功能,JAR 格式已加入擴展機制。擴展機制使 JAR 可通過 manifest Class-Path 頭指定所需其他 JAR。假設 extension1.jar 和 extension2.jar 同目錄,extension1.jar manifest 含:

Class-Path: extension2.jar

表明 extension2.jar 中類是 extension1.jar 中類的擴展類。extension1.jar 中類可調用 extension2.jar 中類,不要求 extension2.jar 在類路徑中。加載使用擴展機制 JAR 時,JVM 高效自動將 Class-Path 頭引用 JAR 添加到類路徑。但擴展 JAR 路徑被解釋為相對路徑,一般擴展 JAR 必須存儲在引用它的 JAR 同目錄。

例:ExtensionClient 引用 ExtensionDemo,捆綁在 ExtensionClient.jar,ExtensionDemo 捆綁在 ExtensionDemo.jar。為使 ExtensionDemo.jar 成擴展,必須將其列在 ExtensionClient.jar manifest Class-Path 頭中:

Manifest-Version: 1.0
Class-Path: ExtensionDemo.jar

Class-Path 值無路徑 ExtensionDemo.jar,表明與 ExtensionClient JAR 同目錄。

JAR 文件安全性

JAR 可用 jarsigner 工具或直接通過 java.security API 簽名。簽名 JAR 與原 JAR 完全相同,只是更新 manifest,在 META-INF 增加簽名文件和簽名塊文件。JAR 用存儲在 Keystore 數據庫中的證書簽名。Keystore 中證書有密碼保護,必須向 jarsigner 提供密碼才能簽名。

圖1 Keystore 數據庫

JAR 每位簽名者由 META-INF 中 .SF 擴展名簽名文件表示。格式類似 manifest — 一組 RFC-822 頭。組成包括主要部分(簽名者提供信息、不針對特定 JAR 項)和一系列單獨項(必須包含在 manifest 中)。驗證簽名 JAR 時,將簽名文件摘要值與 JAR 中相應項計算摘要值比較。

Contents of signature file META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 1.3.0 (Sun Microsystems Inc.)
Name: Sample.java
SHA1-Digest: 3+DdYW8INICtyG8ZarHlFxX0W6g=
Name: Sample.class
SHA1-Digest: YJ5yQHBZBJ3SsTNcHJFqUkfWEmI=
Contents of signature file META-INF/JAMES.SF
Signature-Version: 1.0
SHA1-Digest-Manifest: HBstZOJBuuTJ6QMIdB90T8sjaOM=
Created-By: 1.3.0 (Sun Microsystems Inc.)
Name: Sample.java
SHA1-Digest: qipMDrkurQcKwnyIlI3Jtrnia8Q=
Name: Sample.class
SHA1-Digest: pT2DYby8QXPcCzv2NwpLxd8p4G4=

數字簽名

數字簽名是 .SF 簽名文件已簽名版本。數字簽名文件是二進制文件,與 .SF 同文件名但擴展名不同。根據數字簽名類型(RSA、DSA、PGP)及簽名 JAR 證書類型有不同擴展名。

Keystore

簽名 JAR 必須先有私鑰。私鑰及相關公鑰證書存儲在名為 keystores 的密碼保護數據庫中。JDK 包含創建和修改 keystores 工具。keystore 中每個鑰可用別名標識,通常是擁有鑰簽名者名字。所有 keystore 項(鑰和信任證書項)用唯一別名訪問。別名在用 keytool -genkey 生成鑰對並添加項時指定。後續 keytool 命令必須用同樣別名引用此項。

例:用別名 "james" 生成新公鑰/私鑰對並將公鑰包裝到自簽名證書:

keytool -genkey -alias james -keypass jamespass
-validity 80 -keystore jamesKeyStore
-storepass jamesKeyStorePass

指定初始密碼 "jamespass",後續命令訪問 keystore "jamesKeyStore" 中別名 "james" 相關私鑰需此密碼。若 keystore 不存在,keytool 自動創建。

jarsigner 工具

jarsigner 使用 keystore 生成或驗證 JAR 數字簽名。假設創建了 keystore "jamesKeyStore",含別名 "james" 鑰,簽名 JAR 命令:

jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass
-keypass jamespass -signedjar SSample.jar Sample.jar james

用密碼 "jamesKeyStorePass" 從 "jamesKeyStore" 提取別名 "james"、密碼 "jamespass" 鑰,對 Sample.jar 簽名、創建簽名 JAR SSample.jar。驗證簽名 JAR 更簡單:

jarsigner -verify SSample.jar

若簽名 JAR 未被篡改,jarsigner 會告知 JAR 通過驗證;否則拋出 SecurityException,指明哪些文件未通過驗證。也可用 java.util.jar 和 java.security API 編程簽名,或用 Netscape Object Signing Tool 等工具。

JAR 索引

若應用或 applet 捆綁到多個 JAR,類加載器用簡單線性搜索算法搜索類路徑每個元素,可能下載並打開許多 JAR 直到找到所需類或資源。若類加載器尋找不存在資源,應用或 applet 中所有 JAR 都會下載。對大型網絡應用和 applet,導致啟動緩慢、響應遲緩、浪費帶寬。

JDK 1.3 後,JAR 格式支持索引優化網絡應用中類搜索,特別是 applet。JarIndex 機制收集 applet 或應用中定義所有 JAR 內容,將信息存儲到第一個 JAR 索引文件中。下載第一個 JAR 後,applet 類加載器使用收集內容信息高效加載 JAR。目錄信息存儲在根 JAR META-INF 目錄中 INDEX.LIST 簡單文本文件。

創建 JarIndex

用 jar -i 選項創建。假設目錄結構如圖:

圖2 JarIndex

用命令為 JarIndex_Main.jar、JarIndex_test.jar、SampleDir/JarIndex_test1.jar 創建索引:

jar -i JarIndex_Main.jar JarIndex_test.jar SampleDir/JarIndex_test1.jar

INDEX.LIST 格式簡單,包含每個已索引 JAR 中包含包或類名字:

JarIndex-Version: 1.0
JarIndex_Main.jar
sp
JarIndex_test.jar
Sample
SampleDir/JarIndex_test1.jar
org
org/apache
org/apache/xerces
org/apache/xerces/framework
org/apache/xerces/framework/xml4j

結束語

JAR 格式遠超壓縮格式,有許多可改進效率、安全性和組織 Java 應用功能。因這些功能建立在核心平台(含編譯器和類加載器)中,開發人員可利用 JAR 格式能力簡化和改進開發部署過程。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved