大多數(shù) Java 程序員都熟悉對(duì) JAR 文件的基本操作。但是只有少數(shù)程序員了解 JAR 文件格式的 強(qiáng)大功能 。在本文中,作者探討了JAR 格式的許多功能和優(yōu)勢(shì),包括打包、可執(zhí)行的 JAR 文件、安全性和索引。<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
JAR 文件格式以流行的 ZIP 文件格式為基礎(chǔ),用于將許多個(gè)文件聚集為一個(gè)文件。與 ZIP 文件不同的是,JAR 文件不僅用于壓縮和發(fā)布,而且還用于部署和封裝庫、組件和插件程序,并可被像編譯器和 JVM 這樣的工具直接使用。在 JAR 中包含特殊的文件,如 manifests 和部署描述符,用來指示工具如何處理特定的 JAR。
一個(gè) JAR 文件可以用于:
- 用于發(fā)布和使用類庫
- 作為應(yīng)用程序和擴(kuò)展的構(gòu)建單元
- 作為組件、applet 或者插件程序的部署單位
- 用于打包與組件相關(guān)聯(lián)的輔助資源
JAR 文件格式提供了許多優(yōu)勢(shì)和功能,其中很多是傳統(tǒng)的壓縮格式如 ZIP 或者 TAR 所沒有提供的。它們包括:
-
安全性。
可以對(duì) JAR 文件內(nèi)容加上數(shù)字化簽名。這樣,能夠識(shí)別簽名的工具就可以有選擇地為您授予軟件安全特權(quán),這是其他文件做不到的,它還可以檢測(cè)代碼是否被篡改過。
-
減少下載時(shí)間。
如果一個(gè) applet 捆綁到一個(gè) JAR 文件中,那么瀏覽器就可以在一個(gè) HTTP 事務(wù)中下載這個(gè) applet 的類文件和相關(guān)的資源,而不是對(duì)每一個(gè)文件打開一個(gè)新連接。
-
壓縮。
JAR 格式允許您壓縮文件以提高存儲(chǔ)效率。
-
傳輸平臺(tái)擴(kuò)展。
Java 擴(kuò)展框架(Java Extensions Framework)提供了向 Java 核心平臺(tái)添加功能的方法,這些擴(kuò)展是用 JAR 文件打包的(Java 3D 和 JavaMail 就是由 Sun 開發(fā)的擴(kuò)展例子)。
-
包密封。
存儲(chǔ)在 JAR 文件中的包可以選擇進(jìn)行
密封
,以增強(qiáng)版本一致性和安全性。密封一個(gè)包意味著包中的所有類都必須在同一 JAR 文件中找到。
-
包版本控制。
一個(gè) JAR 文件可以包含有關(guān)它所包含的文件的數(shù)據(jù),如廠商和版本信息。
- 可移植性。 處理 JAR 文件的機(jī)制是 Java 平臺(tái)核心 API 的標(biāo)準(zhǔn)部分。
jar
工具(有關(guān)細(xì)節(jié)參閱
jar
工具
)在默認(rèn)情況下壓縮文件。未壓縮的 JAR 文件一般可以比壓縮過的 JAR 文件更快地裝載,因?yàn)樵谘b載過程中要解壓縮文件,但是未壓縮的文件在網(wǎng)絡(luò)上的下載時(shí)間可能更長(zhǎng)。
大多數(shù) JAR 文件包含一個(gè) META-INF 目錄,它用于存儲(chǔ)包和擴(kuò)展的配置數(shù)據(jù),如安全性和版本信息。Java 2 平臺(tái)識(shí)別并解釋 META-INF 目錄中的下述文件和目錄,以便配置應(yīng)用程序、擴(kuò)展和類裝載器:
-
MANIFEST.MF。
這個(gè)
manifest 文件
定義了與擴(kuò)展和包相關(guān)的數(shù)據(jù)。
-
INDEX.LIST。
這個(gè)文件由
jar
工具的新選項(xiàng)-i
生成,它包含在應(yīng)用程序或者擴(kuò)展中定義的包的位置信息。它是 JarIndex 實(shí)現(xiàn)的一部分,并由類裝載器用于加速類裝載過程。
-
xxx
.SF。
這是 JAR 文件的簽名文件。占位符
xxx
標(biāo)識(shí)了簽名者。
- xxx .DSA。 與簽名文件相關(guān)聯(lián)的簽名程序塊文件,它存儲(chǔ)了用于簽名 JAR 文件的公共簽名。
為了用 JAR 文件執(zhí)行基本的任務(wù),要使用作為Java Development Kit 的一部分提供的 Java Archive Tool (
jar
工具)。用
jar
命令調(diào)用
jar
工具。表 1 顯示了一些常見的應(yīng)用:
功能 | 命令 |
用一個(gè)單獨(dú)的文件創(chuàng)建一個(gè) JAR 文件 | jar cf jar-file input-file... |
用一個(gè)目錄創(chuàng)建一個(gè) JAR 文件 | jar cf jar-file dir-name |
創(chuàng)建一個(gè)未壓縮的 JAR 文件 | jar cf0 jar-file dir-name |
更新一個(gè) JAR 文件 | jar uf jar-file input-file... |
查看一個(gè) JAR 文件的內(nèi)容 | jar tf jar-file |
提取一個(gè) JAR 文件的內(nèi)容 | jar xf jar-file |
從一個(gè) JAR 文件中提取特定的文件 | jar xf jar-file archived-file... |
運(yùn)行一個(gè)打包為可執(zhí)行 JAR 文件的應(yīng)用程序 | java -jar app.jar |
![]() ![]() |
一個(gè) 可執(zhí)行的 jar 文件是一個(gè)自包含的 Java 應(yīng)用程序,它存儲(chǔ)在特別配置的JAR 文件中,可以由 JVM 直接執(zhí)行它而無需事先提取文件或者設(shè)置類路徑。要運(yùn)行存儲(chǔ)在非可執(zhí)行的 JAR 中的應(yīng)用程序,必須將它加入到您的類路徑中,并用名字調(diào)用應(yīng)用程序的主類。但是使用可執(zhí)行的 JAR 文件,我們可以不用提取它或者知道主要入口點(diǎn)就可以運(yùn)行一個(gè)應(yīng)用程序。可執(zhí)行 JAR 有助于方便發(fā)布和執(zhí)行 Java 應(yīng)用程序。
創(chuàng)建一個(gè)可執(zhí)行 JAR 很容易。首先將所有應(yīng)用程序代碼放到一個(gè)目錄中。假設(shè)應(yīng)用程序中的主類是
com.mycompany.myapp.Sample
。您要?jiǎng)?chuàng)建一個(gè)包含應(yīng)用程序代碼的 JAR 文件并標(biāo)識(shí)出主類。為此,在某個(gè)位置(不是在應(yīng)用程序目錄中)創(chuàng)建一個(gè)名為
manifest
的文件,并在其中加入以下一行:
Main-Class: com.mycompany.myapp.Sample |
然后,像這樣創(chuàng)建 JAR 文件:
jar cmf manifest ExecutableJar.jar application-dir |
所要做的就是這些了 -- 現(xiàn)在可以用
java -jar
執(zhí)行這個(gè) JAR 文件 ExecutableJar.jar。
一個(gè)可執(zhí)行的 JAR 必須通過 menifest 文件的頭引用它所需要的所有其他從屬 JAR。如果使用了
-jar
選項(xiàng),那么環(huán)境變量 CLASSPATH 和在命令行中指定的所有類路徑都被 JVM 所忽略。
既然我們已經(jīng)將自己的應(yīng)用程序打包到了一個(gè)名為 ExecutableJar.jar 的可執(zhí)行 JAR 中了,那么我們就可以用下面的命令直接從文件啟動(dòng)這個(gè)應(yīng)用程序:
java -jar ExecutableJar.jar |
![]() ![]() |
![]()
|
密封 JAR 文件中的一個(gè)包意味著在這個(gè)包中定義的所有類都必須在同一個(gè) JAR 文件中找到。這使包的作者可以增強(qiáng)打包類之間的版本一致性。密封還提供了防止代碼篡改的手段。
要密封包,需要在 JAR 的 manifest 文件中為包添加一個(gè)
Name
頭,然后加上值為“true”的
Sealed
頭。與可執(zhí)行的 JAR 一樣,可以在創(chuàng)建 JAR 時(shí),通過指定一個(gè)具有適當(dāng)頭元素的 manifest 文件密封一個(gè) JAR,如下所示:
Name: com/samplePackage/ |
Name
頭標(biāo)識(shí)出包的相對(duì)路徑名。它以一個(gè)“/”結(jié)束以與文件名區(qū)別。在
Name
頭后面第一個(gè)空行之前的所有頭都作用于在
Name
頭中指定的文件或者包。在上述例子中,因?yàn)?
Sealed
頭出現(xiàn)在
Name
頭后并且中間沒有空行,所以
Sealed
頭將被解釋為只應(yīng)用到包
com/samplePackage
上。
如果試圖從密封包所在的 JAR 文件以外的其他地方裝載密封包中的一個(gè)類,那么 JVM 將拋出一個(gè)
SecurityException
。
假設(shè) extension1.jar 和 extension2.jar 是同一個(gè)目錄中的兩個(gè) JAR 文件,extension1.jar 的 manifest 文件包含以下頭:
Class-Path: extension2.jar |
Manifest-Version: 1.0 |
![]() ![]() |
![]()
|
JAR 文件可以用
jarsigner
工具或者直接通過
java.security
API 簽名。一個(gè)簽名的 JAR 文件與原來的 JAR 文件完全相同,只是更新了它的 manifest,并在 META-INF 目錄中增加了兩個(gè)文件,一個(gè)簽名文件和一個(gè)簽名塊文件。
JAR 文件是用一個(gè)存儲(chǔ)在
Keystore
數(shù)據(jù)庫中的證書簽名的。存儲(chǔ)在 keystore 中的證書有密碼保護(hù),必須向
jarsigner
工具提供這個(gè)密碼才能對(duì) JAR 文件簽名。
圖 1. Keystore 數(shù)據(jù)庫
JAR 的每一位簽名者都由在 JAR 文件的 META-INF 目錄中的一個(gè)具有 .SF 擴(kuò)展名的簽名文件表示。這個(gè)文件的格式類似于 manifest 文件 -- 一組 RFC-822 頭。如下所示,它的組成包括一個(gè)主要部分,它包括了由簽名者提供的信息、但是不特別針對(duì)任何特定的 JAR 文件項(xiàng),還有一系列的單獨(dú)的項(xiàng),這些項(xiàng)也必須包含在 menifest 文件中。在驗(yàn)證一個(gè)簽名的 JAR 時(shí),將簽名文件的摘要值與對(duì) JAR 文件中的相應(yīng)項(xiàng)計(jì)算的摘要值進(jìn)行比較。
清單 1. 簽名 JAR 中的 Manifest 和 signature 文件
Contents of signature file META-INF/MANIFEST.MF |
一個(gè)數(shù)字簽名是.SF 簽名文件的已簽名版本。數(shù)字簽名文件是二進(jìn)制文件,并且與 .SF 文件有相同的文件名,但是擴(kuò)展名不同。根據(jù)數(shù)字簽名的類型 -- RSA、DSA 或者 PGP -- 以及用于簽名 JAR 的證書類型而有不同的擴(kuò)展名。
要簽名一個(gè) JAR 文件,必須首先有一個(gè)私鑰。私鑰及其相關(guān)的公鑰證書存儲(chǔ)在名為
keystores
的、有密碼保護(hù)的數(shù)據(jù)庫中。JDK 包含創(chuàng)建和修改 keystores 的工具。keystore 中的每一個(gè)密鑰都可以用一個(gè)別名標(biāo)識(shí),它通常是擁有這個(gè)密鑰的簽名者的名字。
所有 keystore 項(xiàng)(密鑰和信任的證書項(xiàng))都是用唯一別名訪問的。別名是在用
keytool -genkey
命令生成密鑰對(duì)(公鑰和私鑰)并在 keystore 中添加項(xiàng)時(shí)指定的。之后的
keytool
命令必須使用同樣的別名引用這一項(xiàng)。
例如,要用別名“james”生成一個(gè)新的公鑰/私鑰對(duì)并將公鑰包裝到自簽名的證書中,要使用下述命令:
keytool -genkey -alias james -keypass jamespass |
這個(gè)命令序列指定了一個(gè)初始密碼“jamespass”,后續(xù)的命令在訪問 keystore “jamesKeyStore”中與別名“james”相關(guān)聯(lián)的私鑰時(shí),就需要這個(gè)密碼。如果 keystore“jamesKeyStore”不存在,則
keytool
會(huì)自動(dòng)創(chuàng)建它。
jarsigner
工具使用 keystore 生成或者驗(yàn)證 JAR 文件的數(shù)字簽名。
假設(shè)像上述例子那樣創(chuàng)建了 keystore “jamesKeyStore”,并且它包含一個(gè)別名為“james”的密鑰,可以用下面的命令簽名一個(gè) JAR 文件:
jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass |
這個(gè)命令用密碼“jamesKeyStorePass”從名為“jamesKeyStore”的 keystore 中提出別名為“james”、密碼為“jamespass”的密鑰,并對(duì) Sample.jar 文件簽名、創(chuàng)建一個(gè)簽名的 JAR -- SSample.jar。
jarsigner
工具還可以驗(yàn)證一個(gè)簽名的 JAR 文件,這種操作比簽名 JAR 文件要簡(jiǎn)單得多,只需執(zhí)行以下命令:
jarsigner -verify SSample.jar |
如果簽名的 JAR 文件沒有被篡改過,那么
jarsigner
工具就會(huì)告訴您 JAR 通過驗(yàn)證了。否則,它會(huì)拋出一個(gè)
SecurityException
, 表明哪些文件沒有通過驗(yàn)證。
還可以用
java.util.jar
和
java.security
API 以編程方式簽名 JAR(有關(guān)細(xì)節(jié)參閱
參考資料
)。也可以使用像 Netscape Object Signing Tool 這樣的工具。
![]() ![]() |
![]()
|
如果一個(gè)應(yīng)用程序或者 applet 捆綁到多個(gè) JAR 文件中,那么類裝載器就使用一個(gè)簡(jiǎn)單的線性搜索算法搜索類路徑中的每一個(gè)元素,這使類裝載器可能要下載并打開許多個(gè) JAR 文件,直到找到所要的類或者資源。如果類裝載器試圖尋找一個(gè)不存在的資源,那么在應(yīng)用程序或者 applet 中的所有 JAR 文件都會(huì)下載。對(duì)于大型的網(wǎng)絡(luò)應(yīng)用程序和 applet,這會(huì)導(dǎo)致啟動(dòng)緩慢、響應(yīng)遲緩并浪費(fèi)帶寬。
從 JDK 1.3 以后,JAR 文件格式開始支持索引以優(yōu)化網(wǎng)絡(luò)應(yīng)用程序中類的搜索過程,特別是 applet。JarIndex 機(jī)制收集在 applet 或者應(yīng)用程序中定義的所有 JAR 文件的內(nèi)容,并將這些信息存儲(chǔ)到第一個(gè) JAR 文件中的索引文件中。下載了第一個(gè) JAR 文件后,applet 類裝載器將使用收集的內(nèi)容信息高效地裝載 JAR 文件。這個(gè)目錄信息存儲(chǔ)在根 JAR 文件的 META-INF 目錄中的一個(gè)名為 INDEX.LIST 的簡(jiǎn)單文本文件中。
圖 2. JarIndex
您將使用下述命令為 JarIndex_Main.jar、JarIndex_test.jar 和 JarIndex_test1.jar 創(chuàng)建一個(gè)索引文件:
jar -i JarIndex_Main.jar JarIndex_test.jar SampleDir/JarIndex_test1.jar |
INDEX.LIST 文件的格式很簡(jiǎn)單,包含每個(gè)已索引的 JAR 文件中包含的包或者類的名字,如清單 2 所示:
清單 2. JarIndex INDEX.LIST 文件示例
JarIndex-Version: 1.0 |
![]() ![]() |
![]()
|
JAR 格式遠(yuǎn)遠(yuǎn)超出了一種壓縮格式,它有許多可以改進(jìn)效率、安全性和組織 Java 應(yīng)用程序的功能。因?yàn)檫@些功能已經(jīng)建立在核心平臺(tái) -- 包括編譯器和類裝載器 -- 中了,所以開發(fā)人員可以利用 JAR 文件格式的能力簡(jiǎn)化和改進(jìn)開發(fā)和部署過程。.
-
您可以參閱本文在 developerWorks 全球站點(diǎn)上的
英文原文
.
-
參閱
jar
實(shí)用程序的命令行選項(xiàng)的文檔。
-
Raffi Krikorian 在 ONJava 上發(fā)表的文章提供了有關(guān)
programmatically signing a JAR file
的幫助。
-
文章“
Java Web Start
”(
developerWorks
,2001 年 9 月)描述了如何使用這種技術(shù),以便允許應(yīng)用程序可以指定所需的 JAR 文件并動(dòng)態(tài)下載它們。
-
在
developerWorks
Java 技術(shù)專區(qū)
上可以找到數(shù)百篇關(guān)于 Java 編程的各個(gè)方面的文章。
![]() |
||
|
![]() |
Pagadala J. Suresh 是 IBM Global Services India 的軟件工程師。他擅長(zhǎng)的領(lǐng)域包括 Java 技術(shù)、WebSphere Application Server 和 WebSphere Studio Application Developer (WSAD)、Ariba Buyer。他參與了 WebSphere 的 IBM Redbook 項(xiàng)目。可以通過 pjsuresh@in.ibm.com 與 Pagadala 聯(lián)系。 |
![]() |
||
|
![]() |
Palaniyappan Thiagarajan 是位于印度班加羅爾的 IBM Global Services India 的軟件工程師。他是IBM 認(rèn)證的 IBM WebSphere Application Server V3.5 和 IBM DB2 UDB V7.1 Family Fundamentals 專家。可以通過 tpalaniy@in.ibm.com 與 Palaniyappan 聯(lián)系。 |
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
