1、jar簡介
Java歸檔文件格式(Java Archive, JAR)能夠?qū)⒍鄠€源碼溉旋、資源等文件打包到一個歸檔文件中畸冲。這樣,有如下好處:
- 安全性
可以對整個jar包的內(nèi)容進行簽名观腊。 - 減少了下載時間
如果applet被打包成一個jar文件邑闲,那么所有相關(guān)的資源就可以在一個HTTP transaction中下載完成,而無需為每一個文件新建一個連接梧油。 - 壓縮
減少了磁盤空間的占用苫耸。 - 容易擴展
通過jar這種格式,可以和容易地將自己的程序打包提供給別人使用儡陨。 - 包密封(Package Sealing)
存儲在jar文件中的包可以被密封褪子,來保證版本的一致性量淌。密封可以保證一個包中的所有類都來自同一個jar文件。 - 包版本說明
一個jar包可以存儲關(guān)于其內(nèi)容的信息嫌褪,包括提供商呀枢、版本等。 - 可移植性
處理jar文件的機制是Java平臺核心API的標(biāo)準(zhǔn)模塊笼痛。
From docs.oracle.com
2裙秋、jar的使用
JDK自帶的打包工具通過jar
命令來調(diào)用,jar是通過zip格式進行打包的缨伊。所以摘刑,這個jar工具也可以作為日常的壓縮、解壓縮工具來進行使用刻坊。
2.1 jar命令說明
如果安裝了JDK并配置了環(huán)境變量枷恕,在命令行中輸入jar
命令,不加任何參數(shù)紧唱,就可以看到j(luò)ar命令的使用說明活尊,最下面還包含了兩個例子:
jar
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
選項:
-c 創(chuàng)建新檔案
-t 列出檔案目錄
-x 從檔案中提取指定的 (或所有) 文件
-u 更新現(xiàn)有檔案
-v 在標(biāo)準(zhǔn)輸出中生成詳細(xì)輸出
-f 指定檔案文件名
-m 包含指定清單文件中的清單信息
-n 創(chuàng)建新檔案后執(zhí)行 Pack200 規(guī)范化
-e 為捆綁到可執(zhí)行 jar 文件的獨立應(yīng)用程序指定應(yīng)用程序入口點
-0 僅存儲; 不使用任何 ZIP 壓縮
-P 保留文件名中的前導(dǎo) '/' (絕對路徑) 和 ".." (父目錄) 組件
-M 不創(chuàng)建條目的清單文件
-i 為指定的 jar 文件生成索引信息
-C 更改為指定的目錄并包含其中的文件(可以理解為首先cd到指定目錄)
如果任何文件為目錄, 則對其進行遞歸處理。
清單文件名, 檔案文件名和入口點名稱的指定順序與 'm', 'f' 和 'e' 標(biāo)記的指定順序相同漏益。
示例 1: 將兩個類文件歸檔到一個名為 classes.jar 的檔案中:
jar cvf classes.jar Foo.class Bar.class
示例 2: 使用現(xiàn)有的清單文件 'mymanifest' 并將 foo/ 目錄中的所有文件歸檔到 'classes.jar' 中:
jar cvfm classes.jar mymanifest -C foo/ .
摘自<jar命令的幫助文檔>
2.2 jar使用舉例
jar命令打包時默認(rèn)會在jar包中添加清單(manifest)文件蛹锰,如果不想添加,手動指定-M
選項:
>jar -cvf HelloWorld.jar HelloWorld.class #將HelloWorld.class文件打入jar包
已添加清單
正在添加: HelloWorld.class(輸入 = 427) (輸出 = 289)(壓縮了 32%)
>jar -tf HelloWorld.jar #查看歸檔文件的內(nèi)容
META-INF/
META-INF/MANIFEST.MF
HelloWorld.class
>jar -xf HelloWorld.jar META-INF/MANIFEST.MF #解壓出其中的META-INF/MANIFEST.MF文件
>type META-INF\MANIFEST.MF #查看清單文件的內(nèi)容
Manifest-Version: 1.0
Created-By: 1.8.0_51 (Oracle Corporation)
>jar -cvfM HelloWorld.jar HelloWorld.class #將HelloWorld.class文件打入jar包绰疤,不要添加清單文件
正在添加: HelloWorld.class(輸入 = 427) (輸出 = 289)(壓縮了 32%)
>jar -tf HelloWorld.jar
HelloWorld.class
>jar -xf HelloWorld.jar #解壓tar文件到當(dāng)前目錄
如果要生成可以運行的jar包铜犬,需要指定jar包的應(yīng)用程序入口點,用-e選項:
>jar -cvfe HelloWorld.jar HelloWorld HelloWorld.class #創(chuàng)建可以運行的jar包
已添加清單
正在添加: HelloWorld.class(輸入 = 427) (輸出 = 289)(壓縮了 32%)
>jar -tf HelloWorld.jar #查看歸檔的內(nèi)容
META-INF/
META-INF/MANIFEST.MF
HelloWorld.class
>type META-INF\MANIFEST.MF #查看清單文件的內(nèi)容
Manifest-Version: 1.0
Created-By: 1.8.0_51 (Oracle Corporation)
Main-Class: HelloWorld
>java -jar HelloWorld.jar #運行jar包
Hello World!!
查看jar包的文件列表:
jar vtf fileName.jar
3轻庆、清單文件MANIFEST.MF
jar打包時癣猾,會默認(rèn)向jar包中添加一個清單文件(MANIFEST.MF),放在META-INF目錄余爆。上面的例子中纷宇,可以看到:如果指定了jar包的入口程序,清單文件中就會多一行Main-Class: HelloWorld
蛾方。實際上像捶,-e
選項的作用就是向MANIFEST.MF文件中添加這樣一行信息,來聲明jar包的入口程序桩砰。當(dāng)然拓春,我們也可以直接修改清單文件的內(nèi)容。
3.1 修改清單文件的內(nèi)容
前面已經(jīng)說了亚隅,-m
選項可以添加指定清單文件中的清單信息硼莽,格式如下:
jar cfm jar-file manifest-addition input-file(s)
注意:
- manifest-addition是一個已經(jīng)存在的文本文件,其中包含著想要往jar包的清單文件中添加的清單信息煮纵。
- manifest-addition的文件編碼格式必須是UTF-8懂鸵。
- 清單信息每行后面必須有回車或者換行偏螺。(The text file from which you are creating the manifest must end with a new line or carriage return. The last line will not be parsed properly if it does not end with a new line or carriage return.)
- 清單文件名, 檔案文件名和入口點名稱的指定順序與 'm', 'f' 和 'e' 標(biāo)記的指定順序相同。(前面已經(jīng)提到了)
3.2 在清單文件中聲明入口程序
>type manifest.txt #查看清單信息的內(nèi)容
Main-Class: HelloWorld
>jar -cvfm HelloWorld.jar manifest.txt HelloWorld.class #添加清單信息到j(luò)ar包
已添加清單
正在添加: HelloWorld.class(輸入 = 427) (輸出 = 289)(壓縮了 32%)
>jar -xvf HelloWorld.jar META-INF\MANIFEST.MF
已解壓: META-INF/MANIFEST.MF
>type META-INF\MANIFEST.MF
Manifest-Version: 1.0
Created-By: 1.8.0_51 (Oracle Corporation)
Main-Class: HelloWorld #可以看到清單信息成功添加
>java -jar HelloWorld.jar #這樣指定入口程序矾瑰,生成的jar包照樣可以運行砖茸。
Hello World!!
3.3 在清單文件中指定CLASSPATH
在運行java
命令的時候,如果指定了-jar
選項殴穴,那么環(huán)境變量CLASSPATH和在命令行中指定的所有類路徑都被JVM所忽略凉夯。這時,如果一個jar包引用了其它的jar包采幌,解決方案有兩個:
java -cp lib\log4j-1.2.14.jar;hello.jar com.dhn.Hello
(com.dhn.Hello為主類)
在windows下多個jar之間以分號(;)隔開,最后還需要指定運行jar文件中的完整的主類名劲够。-
java -jar hello.jar
這種,需要修改hello.jar中的MANIFEST.MF休傍,通過MANIFEST.MF中的Class-Path 來指定運行時需要用到的其他jar征绎,其他jar可以是當(dāng)前路徑也可以是當(dāng)前路徑下的子目錄。多個jar文件之間以空格隔開磨取。
以下面的MANIFEST.MF文件為例Manifest-Version: 1.0 Main-Class: com.ibm.portalnews.entrance.Main Class-Path: lib\commons-collections-3.2.jar lib\commons-configuration-1.5.jar lib\commons-lang-2.3.jar lib\commons-logging.jar lib\dom4j-1.6.1.jar lib\jaxen-1.1-beta-7.jar lib\jdom.jar lib\log4j-1.2.14.jar
其中:
- Manifest-Version表示版本號人柿,一般由IDE工具(如eclipse)自動生成
Main-Class 是jar文件的主類,程序的入口
Class-Path 指定需要的jar忙厌,多個jar必須要在一行上凫岖,多個jar之間以空格隔開,如果引用的jar在當(dāng)前目錄的子目錄下逢净,windows下使用\來分割哥放,linux下用/分割
文件的冒號后面必須要空一個空格,否則會出錯
文件的最后一行必須是一個回車換行符爹土,否則也會出錯
From: java -jar classpath心得
3.4 將jar包A引用的其它jar包一同打包到A里面
這個問題甥雕,是我一直想的。如果這樣胀茵,那么將一個程序到處拷貝的話就方便的多了社露。然而,這是行不通的琼娘,因為JDK的類加載器不會加載jar包內(nèi)包含的其它jar包中的類呵哨。
當(dāng)然,這樣想過的人不止我一個轨奄,可以通過一些第三方的工具來完成。比如有個工具叫one-jar拒炎,感興趣的可以看下挪拟。
3.5 通過清單文件密封包
JAR中的Package Sealing功能是在Java 1.2引入的。在生成Jar文件時我們可以指定是否將整個Jar或者其中某幾個Package進行密封击你,如果是將Jar文件整個進行密封玉组,那就意味著其內(nèi)所有的Package都被密封了谎柄。Package一旦密封,那么Java 虛擬機一旦成功裝載密封Package中的某個類后惯雳,其后所有裝載的帶有相同Package名的類必須來自同一個Jar文件朝巫,否則將觸發(fā)Sealing Violation安全異常。
對包的密封方式主要有兩種:一種是對jar文件中的某些包進行密封石景,另一種是密封jar中的所有包够掠。
-
對某些包密封腮郊。
Manifest-Version: 1.0 Created-By: 1.8.0_51 (Oracle Corporation) Name: com/test/hello/ Sealed: true Name: com/test/world/ Sealed: true
-
密封jar中的所有包。
Manifest-Version: 1.0 Created-By: 1.8.0_51 (Oracle Corporation) Sealed: true
概括來說,有兩種情況觸發(fā)關(guān)于Sealing的安全異常:
- 檢查當(dāng)前試圖加載的類對應(yīng)的Package是否已經(jīng)被JVM裝載且密封遵绰。如果已經(jīng)被裝載且密封了,但被密封的Package與當(dāng)前加載的類對應(yīng)的Package不是來自同一個Jar文件花枫,將觸發(fā)安全異常黍瞧。
- 檢查當(dāng)前試圖加載的類對應(yīng)的 Package是否已經(jīng)被JVM裝載且密封。如果已經(jīng)被裝載但沒有被密封椎例,但當(dāng)前試圖加載的類對應(yīng)的Package確要試圖進行密封操作挨决,將觸發(fā)安全異常。JVM不允許對已經(jīng)裝載但未密封的Package再進行密封操作订歪。
Package Sealing的好處:
Package Sealing所能帶來的好處主要是版本一致性. 我們知道Java 在運行時是嚴(yán)格按照classpath中定義的順序進行裝載和檢查脖祈,尤其是現(xiàn)在Java開源包滿天飛, 很有可能你的Java應(yīng)用程序或者中間件的classpath中會在不同的Jar文件中包含同一個Package的不同版本。這會使得程序運行產(chǎn)生不一致性結(jié)果陌粹,很難發(fā)現(xiàn)撒犀。