JAR 文件格局供給了許多上風和功效,其中許多是傳統的壓縮格局如 ZIP 或者 TAR 所沒有供給的。它們包含:
☆ 安全性。 可以對 JAR 文件內容加上數字化簽名。這樣,能夠辨認簽名的工具就可以有選擇地為您授予軟件安全特權,這是其他文件做不到的,它還可以檢測代碼是否被修正過。
☆ 減少下載時間。 假如一個 applet ***到一個 JAR 文件中,那麼浏覽器就可以在一個 HTTP 事務中下載這個 applet 的類文件和相干的資源,而不是對每一個文件打開一個新連接。
☆ 壓縮。JAR 格局答應您壓縮文件以提高存儲效率。
☆ 傳輸平台擴大。 Java 擴大框架(Java Extensions Framework)供給了向 Java 核心平台添加功效的方法,這些擴大是用 JAR 文件打包的(Java 3D 和 JavaMail 就是由 Sun 開發的擴大例子)。
☆ 包密封。 存儲在 JAR 文件中的包可以選擇進行密封,以加強版本一致性和安全性。密封一個包意味著包中的所有類都必需在同一 JAR 文件中找到。
☆ 包版本把持。 一個 JAR 文件可以包含有關它所包含的文件的數據,如廠商和版本信息。
☆ 可移植性。 處理 JAR 文件的機制是 Java 平台核心 API 的尺度部分。
壓縮的和未壓縮的 JAR
jar 工具在默認情況下壓縮文件。未壓縮的 JAR 文件一般可以比壓縮過的 JAR 文件更快地裝載,由於在裝載過程中要解壓縮文件,但是未壓縮的文件在網絡上的下載時間可能更長。
META-INF 目錄
大多數 JAR 文件包含一個 META-INF 目錄,它用於存儲包和擴大的配置數據,如安全性和版本信息。Java 2 平台辨認並說明 META-INF 目錄中的下述文件和目錄,以便配置利用程序、擴大和類裝載器:
☆ MANIFEST.MF。 這個 manifest 文件定義了與擴大和包相干的數據。
☆ INDEX.LIST。 這個文件由 jar 工具的新選項 -i 天生,它包含在利用程序或者擴大中定義的包的地位信息。它是 JarIndex 實現的一部分,並由類裝載器用於加速類裝載過程。
☆ ***.SF。 這是 JAR 文件的簽名文件。占位符 *** 標識了簽名者。
☆ ***.DSA。 與簽名文件相干聯的簽名程序塊文件,它存儲了用於簽名 JAR 文件的公共簽名。
jar 工具
為了用 JAR 文件履行基礎的任務,要應用作為Java Development Kit 的一部分供給的 Java Archive Tool (jar 工具)。用 jar 命令調用 jar 工具。表 1 顯示了一些常見的利用:
表 1. 常見的 jar 工具用法
功效 命令
用一個單獨的文件創立一個 JAR 文件 jar cf jar-file input-file...
用一個目錄創立一個 JAR 文件 jar cf jar-file dir-name
創立一個未壓縮的 JAR 文件 jar cf0 jar-file dir-name
更新一個 JAR 文件 jar uf jar-file input-file...
查看一個 JAR 文件的內容 jar tf jar-file
提取一個 JAR 文件的內容 jar xf jar-file
從一個 JAR 文件中提取特定的文件 jar xf jar-file archived-file...
運行一個打包為可履行 JAR 文件的利用程序 Java -jar app.jar
可履行的 JAR
一個可履行的 jar 文件是一個自包含的 Java 利用程序,它存儲在特別配置的JAR 文件中,可以由 JVM 直接履行它而無需事先提取文件或者設置類路徑。要運行存儲在非可履行的 JAR 中的利用程序,必需將它加進到您的類路徑中,並用名字調用利用程序的主類。但是應用可履行的 JAR 文件,我們可以不用提取它或者知道重要進口點就可以運行一個利用程序。可履行 JAR 有助於方便宣布和履行 Java 利用程序。
創立可履行 JAR
創立一個可履行 JAR 很輕易。首先將所有利用程序代碼放到一個目錄中。假設利用程序中的主類是 com.mycompany.myapp.Sample。您要創立一個包含利用程序代碼的 JAR 文件並標識出主類。為此,在某個地位(不是在利用程序目錄中)創立一個名為 manifest 的文件,並在其中加進以下一行:
Main-Class: com.mycompany.myapp.Sample
然後,像這樣創立 JAR 文件:
jar cmf manifest ExecutableJar.jar application-dir
所要做的就是這些了 -- 現在可以用 Java -jar 履行這個 JAR 文件 ExecutableJar.jar。
一個可履行的 JAR 必需通過 menifest 文件的頭引用它所需要的所有其他附屬 JAR。假如應用了 -jar 選項,那麼環境變量 CLASSPATH 和在命令行中指定的所有類路徑都被 JVM 所疏忽。
啟動可履行 JAR
既然我們已經將自己的利用程序打包到了一個名為 ExecutableJar.jar 的可履行 JAR 中了,那麼我們就可以用下面的命令直接從文件啟動這個利用程序:
Java -jar ExecutableJar.jar
包密封
密封 JAR 文件中的一個包意味著在這個包中定義的所有類都必需在同一個 JAR 文件中找到。這使包的作者可以加強打包類之間的版本一致性。密封還供給了防止代碼修正的手段。
要密封包,需要在 JAR 的 manifest 文件中為包添加一個 Name 頭,然後加上值為“true”的 Sealed 頭。與可履行的 JAR 一樣,可以在創立 JAR 時,通過指定一個具有適當頭元素的 manifest 文件密封一個 JAR,如下所示:
Name: com/samplePackage/
Sealed: true
Name 頭標識出包的相對路徑名。它以一個“/”結束以與文件名差別。在 Name 頭後面第一個空行之前的所有頭都作用於在 Name 頭中指定的文件或者包。在上述例子中,由於 Sealed 頭呈現在 Name 頭後並且中間沒有空行,所以 Sealed 頭將被說明為只利用到包 com/samplePackage 上。
假如試圖從密封包所在的 JAR 文件以外的其他處所裝載密封包中的一個類,那麼 JVM 將拋出一個 SecurityException。
擴大打包
擴大為 Java 平台增加了功效,在 JAR 文件格局中已經加進了擴大機制。擴大機制使得 JAR 文件可以通過 manifest 文件中的 Class-Path 頭指定所需要的其他 JAR 文件。
假設 extension1.jar 和 extension2.jar 是同一個目錄中的兩個 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 的 JAR 文件中,而類 ExtensionDemo 則***在 ExtensionDemo.jar 中。為了使 ExtensionDemo.jar 可以成為擴大,必需將 ExtensionDemo.jar 列在 ExtensionClIEnt.jar 的 manifest 的 Class-Path 頭中,如下所示:
Manifest-Version: 1.0
Class-Path: ExtensionDemo.jar
在這個 manifest 中 Class-Path 頭的值是沒有指定路徑的 ExtensionDemo.jar,表明 ExtensionDemo.jar 與 ExtensionClIEnt JAR 文件處在同一目錄中。
JAR 文件中的安全性
JAR 文件可以用 jarsigner 工具或者直接通過 Java.security API 簽名。一個簽名的 JAR 文件與本來的 JAR 文件完整雷同,只是更新了它的 manifest,並在 META-INF 目錄中增加了兩個文件,一個簽名文件和一個簽名塊文件。
JAR 文件是用一個存儲在 Keystore 數據庫中的證書簽名的。存儲在 keystore 中的證書有密碼保護,必需向 jarsigner 工具供給這個密碼才干對 JAR 文件簽名。
JAR 的每一位簽名者都由在 JAR 文件的 META-INF 目錄中的一個具有 .SF 擴大名的簽名文件表現。這個文件的格局類似於 manifest 文件 -- 一組 RFC-822 頭。如下所示,它的組成包含一個重要部分,它包含了由簽名者供給的信息、但是不特別針對任何特定的 JAR 文件項,還有一系列的單獨的項,這些項也必需包含在 menifest 文件中。在驗證一個簽名的 JAR 時,將簽名文件的摘要值與對 JAR 文件中的相應項盤算的摘要值進行比擬。
清單 1. 簽名 JAR 中的 Manifest 和 signature 文件
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 命令天生密鑰對(公鑰和私鑰)並在 keystore 中添加項時指定的。之後的 keytool 命令必需應用同樣的別號引用這一項。
例如,要用別號“james”天生一個新的公鑰/私鑰對並將公鑰包裝到自簽名的證書中,要應用下述命令:
keytool -genkey -alias james -keypass jamespass
-validity 80 -keystore jamesKeyStore
-storepass jamesKeyStorePass
這個命令序列指定了一個初始密碼“jamespass”,後續的命令在拜訪 keystore “jamesKeyStore”中與別號“james”相干聯的私鑰時,就需要這個密碼。假如 keystore“jamesKeyStore”不存在,則 keytool 會主動創立它。
jarsigner 工具
jarsigner 工具應用 keystore 天生或者驗證 JAR 文件的數字簽名。
假設像上述例子那樣創立了 keystore “jamesKeyStore”,並且它包含一個別號為“james”的密鑰,可以用下面的命令簽名一個 JAR 文件:
jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass
-keypass jamespass -signedjar SSample.jar Sample.jar james
這個命令用密碼“jamesKeyStorePass”從名為“jamesKeyStore”的 keystore 中提出別號為“james”、密碼為“jamespass”的密鑰,並對 Sample.jar 文件簽名、創立一個簽名的 JAR -- SSample.jar。
jarsigner 工具還可以驗證一個簽名的 JAR 文件,這種把持比簽名 JAR 文件要簡略得多,只需履行以下命令:
jarsigner -verify SSample.jar
假如簽名的 JAR 文件沒有被修正過,那麼 jarsigner 工具就會告訴您 JAR 通過驗證了。否則,它會拋出一個 SecurityException, 表明哪些文件沒有通過驗證。
還可以用 java.util.jar 和 Java.security API 以編程方法簽名 JAR(有關細節參閱參考材料)。也可以應用像 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 選項創立一個 JarIndex。
您將應用下述命令為 JarIndex_Main.jar、JarIndex_test.jar 和 JarIndex_test1.jar 創立一個索引文件:
jar -i JarIndex_Main.jar JarIndex_test.jar SampleDir/JarIndex_test1.jar
INDEX.LIST 文件的格局很簡略,包含每個已索引的 JAR 文件中包含的包或者類的名字,如清單 2 所示:
清單 2. JarIndex INDEX.LIST 文件示例
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 文件格局的才能簡化和改良開發和安排過程。