JAR 文件是什么?
JAR 文件格式以流行的 ZIP 文件格式為基礎(chǔ)扬卷,用于將許多個文件聚集為一個文件怪得。與 ZIP 文件不同的是,JAR 文件不僅用于壓縮和發(fā)布蚕断,而且還用于部署和封裝庫亿乳、組件和插件程序径筏,并可被像編譯器和 JVM 這樣的工具直接使用滋恬。在 JAR 中包含特殊的文件,如 manifests 和部署描述符带斑,用來指示工具如何處理特定的 JAR勋磕。
一個 JAR 文件可以用于:
- 用于發(fā)布和使用類庫
- 作為應(yīng)用程序和擴展的構(gòu)建單元
- 作為組件指黎、applet 或者插件程序的部署單位
- 用于打包與組件相關(guān)聯(lián)的輔助資源
JAR 文件格式提供了許多++優(yōu)勢++和++功能++醋安,其中很多是傳統(tǒng)的壓縮格式如 ZIP 或者 TAR 所沒有提供的墓毒。它們包括:
- 安全性所计≈麟剩可以對 JAR 文件內(nèi)容加上數(shù)字化簽名习勤。這樣图毕,能夠識別簽名的工具就可以有選擇地為您授予軟件安全特權(quán),這是其他文件做不到的囤官,它還可以++檢測代碼是否被篡改過++党饮。
- 減少下載時間驳庭。如果一個 applet 捆綁到一個 JAR 文件中嚷掠,那么瀏覽器就可以在一個 HTTP 事務(wù)中下載這個 applet 的類文件和相關(guān)的資源,而不是對每一個文件打開一個新連接贯城。
-
壓縮能犯。JAR 格式允許您壓縮文件以提高存儲效率踩晶。
傳輸平臺擴展枕磁。Java 擴展框架 (Java Extensions Framework) 提供了向 Java 核心平臺添加功能的方法,這些擴展是用 JAR 文件打包的 (Java 3D 和 JavaMail 就是由 Sun 開發(fā)的擴展例子 )排苍。 - 包密封学密。存儲在 JAR 文件中的包可以選擇進行 密封腻暮,以增強版本一致性和安全性。密封一個包意味著包中的所有類都必須在同一 JAR 文件中找到具垫。
- 包版本控制做修。一個 JAR 文件可以包含有關(guān)它所包含的文件的數(shù)據(jù)抡草,如廠商和版本信息康震。
- 可移植性宾濒。處理 JAR 文件的機制是 Java 平臺核心 API 的標準部分绘梦。
壓縮的和未壓縮的 JAR
jar工具 ( 有關(guān)細節(jié)參閱 jar 工具 ) 在默認情況下壓縮文件。未壓縮的 JAR 文件一般可以比壓縮過的 JAR 文件更快地裝載钝诚,因為在裝載過程中要解壓縮文件凝颇,但是未壓縮的文件在網(wǎng)絡(luò)上的下載時間可能更長疹鳄。
META-INF 目錄
大多數(shù) JAR 文件包含一個 META-INF 目錄瘪弓,它用于存儲包和擴展的配置數(shù)據(jù),如安全性和版本信息袱饭。Java 2 平臺識別并解釋 META-INF 目錄中的下述文件和目錄宁赤,以便配置應(yīng)用程序、擴展和類裝載器:
- MANIFEST.MF愕够。這個 manifest 文件定義了與擴展和包相關(guān)的數(shù)據(jù)惑芭。
- INDEX.LIST遂跟。這個文件由 jar工具的新選項 -i生成婴渡,它包含在應(yīng)用程序或者擴展中定義的包的位置信息。它是 JarIndex 實現(xiàn)的一部分哄尔,并由類裝載器用于加速類裝載過程岭接。
- xxx.SF臼予。 這是 JAR 文件的簽名文件粘拾。占位符 xxx標識了簽名者。
- xxx.DSA酬滤。 與簽名文件相關(guān)聯(lián)的簽名程序塊文件盯串,它存儲了用于簽名 JAR 文件的公共簽名体捏。
jar 工具
為了用 JAR 文件執(zhí)行基本的任務(wù),要使用作為 Java Development Kit 的一部分提供的 Java Archive Tool ( jar工具 )河泳。用 jar命令調(diào)用 jar工具拆挥。表 1 顯示了一些常見的應(yīng)用:
常見的 jar工具用法:
功能 | 命令 |
---|---|
用一個單獨的文件創(chuàng)建一個 JAR 文件 | jar cf jar-file input-file... |
用一個目錄創(chuàng)建一個JAR 文件 | jar cf jar-file dir-name |
創(chuàng)建一個未壓縮的JAR 文件 | jar cf0 jar-file dir-name |
更新一個 JAR 文件 | jar uf jar-file input-file... |
查看一個 JAR 文件的內(nèi)容 | jar tf jar-file |
提取一個 JAR 文件的內(nèi)容 | jar xf jar-file |
從一個 JAR 文件中提取特定的文件 | jar xf jar-file archived-file... |
運行一個打包為可執(zhí)行 JAR 文件的應(yīng)用程序 | java -jar app.jar |
可執(zhí)行的 JAR
一個 可執(zhí)行的 jar文件是一個自包含的 Java 應(yīng)用程序纸兔,它存儲在特別配置的 JAR 文件中汉矿,可以由 JVM 直接執(zhí)行它而無需事先提取文件或者設(shè)置類路徑备禀。要運行存儲在非可執(zhí)行的 JAR 中的應(yīng)用程序曲尸,必須將它加入到您的類路徑中,并用名字調(diào)用應(yīng)用程序的主類蚕捉。但是使用可執(zhí)行的 JAR 文件,我們可以不用提取它或者知道主要入口點就可以運行一個應(yīng)用程序秘通》蜗。可執(zhí)行 JAR 有助于方便發(fā)布和執(zhí)行 Java 應(yīng)用程序。
創(chuàng)建可執(zhí)行 JAR
創(chuàng)建一個可執(zhí)行 JAR 很容易夕吻。首先將所有應(yīng)用程序代碼放到一個目錄中涉馅。假設(shè)應(yīng)用程序中的主類是 com.mycompany.myapp.Sample黄虱。您要創(chuàng)建一個包含應(yīng)用程序代碼的 JAR 文件并標識出主類。為此桥爽,在某個位置 ( 不是在應(yīng)用程序目錄中 ) 創(chuàng)建一個名為 manifest的文件昧识,并在其中加入以下一行:
Main-Class: com.mycompany.myapp.Sample
然后跪楞,像這樣創(chuàng)建 JAR 文件:
jar cmf manifest ExecutableJar.jar application-dir
所要做的就是這些了 -- 現(xiàn)在可以用 java -jar執(zhí)行這個 JAR 文件 ExecutableJar.jar。
一個可執(zhí)行的 JAR 必須通過 menifest 文件的頭引用它所需要的所有其他從屬 JAR朵耕。如果使用了 -jar選項阎曹,那么環(huán)境變量 CLASSPATH 和在命令行中指定的所有類路徑都被 JVM 所忽略处嫌。
啟動可執(zhí)行 JAR
既然我們已經(jīng)將自己的應(yīng)用程序打包到了一個名為 ExecutableJar.jar 的可執(zhí)行 JAR 中了斟湃,那么我們就可以用下面的命令直接從文件啟動這個應(yīng)用程序:
java -jar ExecutableJar.jar
包密封
密封 JAR 文件中的一個包意味著在這個包中定義的所有類都必須在同一個 JAR 文件中找到凝赛。這使包的作者可以增強打包類之間的版本一致性。密封還提供了防止代碼篡改的手段捆昏。
要密封包骗卜,需要在 JAR 的 manifest 文件中為包添加一個 Name頭左胞,然后加上值為“true”的 Sealed頭烤宙。與可執(zhí)行的 JAR 一樣,可以在創(chuàng)建 JAR 時乳愉,通過指定一個具有適當頭元素的 manifest 文件密封一個 JAR,如下所示:
Name: com/samplePackage/
Sealed: true
Name頭標識出包的相對路徑名捕虽。它以一個“/”結(jié)束以與文件名區(qū)別坡脐。在 Name頭后面第一個空行之前的所有頭都作用于在 Name頭中指定的文件或者包。在上述例子中备闲,因為 Sealed頭出現(xiàn)在 Name 頭后并且中間沒有空行恬砂,所以 Sealed頭將被解釋為只應(yīng)用到包 com/samplePackage 上。
如果試圖從密封包所在的 JAR 文件以外的其他地方裝載密封包中的一個類漆羔,那么 JVM 將拋出一個 SecurityException演痒。
擴展打包
擴展為 Java 平臺增加了功能趋惨,在 JAR 文件格式中已經(jīng)加入了擴展機制器虾。擴展機制使得 JAR 文件可以通過 manifest 文件中的 Class-Path頭指定所需要的其他 JAR 文件。
假設(shè) extension1.jar 和 extension2.jar 是同一個目錄中的兩個 JAR 文件端姚,extension1.jar 的 manifest 文件包含以下頭:
Class-Path: extension2.jar
這個頭表明 extension2.jar 中的類是 extension1.jar 中的類的 擴展類。extension1.jar 中的類可以調(diào)用 extension2.jar 中的類巫湘,并且不要求 extension2.jar 處在類路徑中尚氛。
在裝載使用擴展機制的 JAR 時,JVM 會高效而自動地將在 Class-Path頭中引用的 JAR 添加到類路徑中属瓣。不過,擴展 JAR 路徑被解釋為相對路徑护昧,所以一般來說惋耙,擴展 JAR 必須存儲在引用它的 JAR 所在的同一目錄中熊昌。
例如婿屹,假設(shè)類 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.securityAPI 簽名。一個簽名的 JAR 文件與原來的 JAR 文件完全相同婉徘,只是更新了它的 manifest咐汞,并在 META-INF 目錄中增加了兩個文件化撕,一個簽名文件和一個簽名塊文件。
JAR 文件是用一個存儲在 Keystore數(shù)據(jù)庫中的證書簽名的蟹瘾。存儲在 keystore 中的證書有密碼保護,必須向 jarsigner工具提供這個密碼才能對 JAR 文件簽名憾朴。
JAR 的每一位簽名者都由在 JAR 文件的 META-INF 目錄中的一個具有 .SF 擴展名的簽名文件表示。這個文件的格式類似于 manifest 文件 -- 一組 RFC-822 頭府寒。如下所示株搔,它的組成包括一個主要部分纯蛾,它包括了由簽名者提供的信息翻诉、但是不特別針對任何特定的 JAR 文件項,還有一系列的單獨的項舒岸,這些項也必須包含在 menifest 文件中蛾派。在驗證一個簽名的 JAR 時个少,將簽名文件的摘要值與對 JAR 文件中的相應(yīng)項計算的摘要值進行比較。
簽名 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=
數(shù)字簽名
一個數(shù)字簽名是 .SF 簽名文件的已簽名版本壳澳。數(shù)字簽名文件是二進制文件巷波,并且與 .SF 文件有相同的文件名褥紫,但是擴展名不同瞪慧。根據(jù)數(shù)字簽名的類型 -- RSA弃酌、DSA 或者 PGP -- 以及用于簽名 JAR 的證書類型而有不同的擴展名。
Keystore
要簽名一個 JAR 文件查蓉,必須首先有一個私鑰榜贴。私鑰及其相關(guān)的公鑰證書存儲在名為 keystores的唬党、有密碼保護的數(shù)據(jù)庫中。JDK 包含創(chuàng)建和修改 keystores 的工具轻要。keystore 中的每一個密鑰都可以用一個別名標識,它通常是擁有這個密鑰的簽名者的名字浮还。
所有 keystore 項 ( 密鑰和信任的證書項 ) 都是用唯一別名訪問的剔难。別名是在用 keytool -genkey 命令生成密鑰對 ( 公鑰和私鑰 ) 并在 keystore 中添加項時指定的慕嚷。之后的 keytool命令必須使用同樣的別名引用這一項露懒。
例如,要用別名“james”生成一個新的公鑰 / 私鑰對并將公鑰包裝到自簽名的證書中蛇耀,要使用下述命令:
keytool -genkey -alias james -keypass jamespass
-validity 80 -keystore jamesKeyStore
-storepass jamesKeyStorePass
這個命令序列指定了一個初始密碼“jamespass”纺涤,后續(xù)的命令在訪問 keystore “jamesKeyStore”中與別名“james”相關(guān)聯(lián)的私鑰時,就需要這個密碼撩炊。如果 keystore“jamesKeyStore”不存在拧咳,則 keytool會自動創(chuàng)建它囚灼。
jarsigner 工具
jarsigner工具使用 keystore 生成或者驗證 JAR 文件的數(shù)字簽名。
假設(shè)像上述例子那樣創(chuàng)建了 keystore “jamesKeyStore”掐暮,并且它包含一個別名為“james”的密鑰政钟,可以用下面的命令簽名一個 JAR 文件:
jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass
-keypass jamespass -signedjar SSample.jar Sample.jar james
這個命令用密碼“jamesKeyStorePass”從名為“jamesKeyStore”的 keystore 中提出別名為“james”养交、密碼為“jamespass”的密鑰,并對 Sample.jar 文件簽名殖妇、創(chuàng)建一個簽名的 JAR -- SSample.jar破花。
jarsigner工具還可以驗證一個簽名的 JAR 文件座每,這種操作比簽名 JAR 文件要簡單得多峭梳,只需執(zhí)行以下命令:
jarsigner -verify SSample.jar
如果簽名的 JAR 文件沒有被篡改過,那么 jarsigner工具就會告訴您 JAR 通過驗證了捂寿。否則秦陋,它會拋出一個 SecurityException驳概, 表明哪些文件沒有通過驗證顺又。
還可以用 java.util.jar和 java.securityAPI 以編程方式簽名 JAR( 有關(guān)細節(jié)參閱 參考資料)等孵。也可以使用像 Netscape Object Signing Tool 這樣的工具。
JAR 索引
如果一個應(yīng)用程序或者 applet 捆綁到多個 JAR 文件中锐锣,那么類裝載器就使用一個簡單的線性搜索算法搜索類路徑中的每一個元素雕憔,這使類裝載器可能要下載并打開許多個 JAR 文件斤彼,直到找到所要的類或者資源。如果類裝載器試圖尋找一個不存在的資源蘸泻,那么在應(yīng)用程序或者 applet 中的所有 JAR 文件都會下載琉苇。對于大型的網(wǎng)絡(luò)應(yīng)用程序和 applet,這會導(dǎo)致啟動緩慢悦施、響應(yīng)遲緩并浪費帶寬并扇。
從 JDK 1.3 以后,JAR 文件格式開始支持索引以優(yōu)化網(wǎng)絡(luò)應(yīng)用程序中類的搜索過程抡诞,特別是 applet穷蛹。JarIndex 機制收集在 applet 或者應(yīng)用程序中定義的所有 JAR 文件的內(nèi)容,并將這些信息存儲到第一個 JAR 文件中的索引文件中昼汗。下載了第一個 JAR 文件后肴熏,applet 類裝載器將使用收集的內(nèi)容信息高效地裝載 JAR 文件。這個目錄信息存儲在根 JAR 文件的 META-INF 目錄中的一個名為 INDEX.LIST 的簡單文本文件中蛙吏。
創(chuàng)建一個 JarIndex
可以通過在 jar命令中指定 -i選項創(chuàng)建一個 JarIndex。假設(shè)我們的目錄結(jié)構(gòu)如下圖所示:
|- jarIndex
jarIndex_Main,JarIndex_test.jar
|-- SampleDir
JarIndex_test1.jar
您將使用下述命令為 JarIndex_Main.jar泼诱、JarIndex_test.jar 和 JarIndex_test1.jar 創(chuàng)建一個索引文件:
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
結(jié)束語
JAR 格式遠遠超出了一種壓縮格式,它有許多可以改進效率骗绕、安全性和組織 Java 應(yīng)用程序的功能。因為這些功能已經(jīng)建立在核心平臺 -- 包括編譯器和類裝載器 -- 中了撤缴,所以開發(fā)人員可以利用 JAR 文件格式的能力簡化和改進開發(fā)和部署過程。.
您可以參閱本文在 developerWorks 全球站點上的 英文原文.
參閱 jar 實用程序的命令行選項的文檔.
Raffi Krikorian 在 ONJava 上發(fā)表的文章提供了有關(guān) programmatically signing a JAR file的幫助。
文章“Java Web Start”( developerWorks钉稍,2001 年 9 月 ) 描述了如何使用這種技術(shù)种樱,以便允許應(yīng)用程序可以指定所需的 JAR 文件并動態(tài)下載它們。
在 developerWorks Java 技術(shù)專區(qū) 上可以找到數(shù)百篇關(guān)于 Java 編程的各個方面的文章。