Java之jar打包

1、jar簡介

Java歸檔文件格式(Java Archive, JAR)能夠將多個源碼、資源等文件打包到一個歸檔文件中。這樣,有如下好處:

  • 安全性
    可以對整個jar包的內容進行簽名。
  • 減少了下載時間
    如果applet被打包成一個jar文件,那么所有相關的資源就可以在一個HTTP transaction中下載完成,而無需為每一個文件新建一個連接。
  • 壓縮
    減少了磁盤空間的占用。
  • 容易擴展
    通過jar這種格式,可以和容易地將自己的程序打包提供給別人使用。
  • 包密封(Package Sealing)
    存儲在jar文件中的包可以被密封,來保證版本的一致性。密封可以保證一個包中的所有類都來自同一個jar文件。
  • 包版本說明
    一個jar包可以存儲關于其內容的信息,包括提供商、版本等。
  • 可移植性
    處理jar文件的機制是Java平臺核心API的標準模塊。

From docs.oracle.com

2、jar的使用

JDK自帶的打包工具通過jar命令來調用,jar是通過zip格式進行打包的。所以,這個jar工具也可以作為日常的壓縮、解壓縮工具來進行使用。

2.1 jar命令說明

如果安裝了JDK并配置了環境變量,在命令行中輸入jar命令,不加任何參數,就可以看到jar命令的使用說明,最下面還包含了兩個例子:

jar
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
選項:
    -c  創建新檔案
    -t  列出檔案目錄
    -x  從檔案中提取指定的 (或所有) 文件
    -u  更新現有檔案
    -v  在標準輸出中生成詳細輸出
    -f  指定檔案文件名
    -m  包含指定清單文件中的清單信息
    -n  創建新檔案后執行 Pack200 規范化
    -e  為捆綁到可執行 jar 文件的獨立應用程序指定應用程序入口點
    -0  僅存儲; 不使用任何 ZIP 壓縮
    -P  保留文件名中的前導 '/' (絕對路徑) 和 ".." (父目錄) 組件
    -M  不創建條目的清單文件
    -i  為指定的 jar 文件生成索引信息
    -C  更改為指定的目錄并包含其中的文件(可以理解為首先cd到指定目錄)
如果任何文件為目錄, 則對其進行遞歸處理。
清單文件名, 檔案文件名和入口點名稱的指定順序與 'm', 'f' 和 'e' 標記的指定順序相同。

示例 1: 將兩個類文件歸檔到一個名為 classes.jar 的檔案中:
       jar cvf classes.jar Foo.class Bar.class
示例 2: 使用現有的清單文件 'mymanifest' 并將 foo/ 目錄中的所有文件歸檔到 'classes.jar' 中:
       jar cvfm classes.jar mymanifest -C foo/ .

摘自<jar命令的幫助文檔>

2.2 jar使用舉例

jar命令打包時默認會在jar包中添加清單(manifest)文件,如果不想添加,手動指定-M選項:

>jar -cvf HelloWorld.jar HelloWorld.class   #將HelloWorld.class文件打入jar包
    已添加清單
    正在添加: HelloWorld.class(輸入 = 427) (輸出 = 289)(壓縮了 32%)
>jar -tf HelloWorld.jar   #查看歸檔文件的內容
    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   #查看清單文件的內容
    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文件到當前目錄

如果要生成可以運行的jar包,需要指定jar包的應用程序入口點,用-e選項:

>jar -cvfe HelloWorld.jar HelloWorld HelloWorld.class   #創建可以運行的jar包
    已添加清單
    正在添加: HelloWorld.class(輸入 = 427) (輸出 = 289)(壓縮了 32%)
>jar -tf HelloWorld.jar   #查看歸檔的內容
    META-INF/
    META-INF/MANIFEST.MF
    HelloWorld.class
>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!!

查看jar包的文件列表:

jar vtf  fileName.jar

3、清單文件MANIFEST.MF

jar打包時,會默認向jar包中添加一個清單文件(MANIFEST.MF),放在META-INF目錄。上面的例子中,可以看到:如果指定了jar包的入口程序,清單文件中就會多一行Main-Class: HelloWorld。實際上,-e選項的作用就是向MANIFEST.MF文件中添加這樣一行信息,來聲明jar包的入口程序。當然,我們也可以直接修改清單文件的內容。

3.1 修改清單文件的內容

前面已經說了,-m選項可以添加指定清單文件中的清單信息,格式如下:

jar cfm jar-file manifest-addition input-file(s)

注意:

  • manifest-addition是一個已經存在的文本文件,其中包含著想要往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' 標記的指定順序相同。(前面已經提到了)

3.2 在清單文件中聲明入口程序

>type manifest.txt   #查看清單信息的內容
    Main-Class: HelloWorld
    
>jar -cvfm HelloWorld.jar manifest.txt HelloWorld.class   #添加清單信息到jar包
    已添加清單
    正在添加: 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選項,那么環境變量CLASSPATH和在命令行中指定的所有類路徑都被JVM所忽略。這時,如果一個jar包引用了其它的jar包,解決方案有兩個:

  1. java -cp lib\log4j-1.2.14.jar;hello.jar com.dhn.Hello (com.dhn.Hello為主類)
    在windows下多個jar之間以分號(;)隔開,最后還需要指定運行jar文件中的完整的主類名。

  2. java -jar hello.jar
    這種,需要修改hello.jar中的MANIFEST.MF,通過MANIFEST.MF中的Class-Path 來指定運行時需要用到的其他jar,其他jar可以是當前路徑也可以是當前路徑下的子目錄。多個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在當前目錄的子目錄下,windows下使用\來分割,linux下用/分割
      
    • 文件的冒號后面必須要空一個空格,否則會出錯
      
    • 文件的最后一行必須是一個回車換行符,否則也會出錯
      

    From: java -jar classpath心得

3.4 將jar包A引用的其它jar包一同打包到A里面

這個問題,是我一直想的。如果這樣,那么將一個程序到處拷貝的話就方便的多了。然而,這是行不通的,因為JDK的類加載器不會加載jar包內包含的其它jar包中的類。

當然,這樣想過的人不止我一個,可以通過一些第三方的工具來完成。比如有個工具叫one-jar,感興趣的可以看下。

3.5 通過清單文件密封包

JAR中的Package Sealing功能是在Java 1.2引入的。在生成Jar文件時我們可以指定是否將整個Jar或者其中某幾個Package進行密封,如果是將Jar文件整個進行密封,那就意味著其內所有的Package都被密封了。Package一旦密封,那么Java 虛擬機一旦成功裝載密封Package中的某個類后,其后所有裝載的帶有相同Package名的類必須來自同一個Jar文件,否則將觸發Sealing Violation安全異常。

From Java中Package Sealing的探秘之旅

對包的密封方式主要有兩種:一種是對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
    

概括來說,有兩種情況觸發關于Sealing的安全異常:

  1. 檢查當前試圖加載的類對應的Package是否已經被JVM裝載且密封。如果已經被裝載且密封了,但被密封的Package與當前加載的類對應的Package不是來自同一個Jar文件,將觸發安全異常。
  2. 檢查當前試圖加載的類對應的 Package是否已經被JVM裝載且密封。如果已經被裝載但沒有被密封,但當前試圖加載的類對應的Package確要試圖進行密封操作,將觸發安全異常。JVM不允許對已經裝載但未密封的Package再進行密封操作。

Package Sealing的好處:
Package Sealing所能帶來的好處主要是版本一致性. 我們知道Java 在運行時是嚴格按照classpath中定義的順序進行裝載和檢查,尤其是現在Java開源包滿天飛, 很有可能你的Java應用程序或者中間件的classpath中會在不同的Jar文件中包含同一個Package的不同版本。這會使得程序運行產生不一致性結果,很難發現。

From: Java中Package Sealing的探秘之旅

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,947評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,094評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,485評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,268評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,817評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,039評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,551評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,502評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,662評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,907評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,304評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,563評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,255評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,637評論 2 370

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,775評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,885評論 6 342
  • 來可以 但不能賴著不走
    你怎么想的閱讀 387評論 0 0
  • 接下來要寫的文字屬于2014年。 在微博上,跨年的鐘聲敲響,每個人都在說新年快樂,對節日無感的我,也被渲染得發了一...
  • 納蘭性德的這首《長相思山一程》,寫盡千山萬里情。 山一程,水一程,身向榆關那畔行,夜深千帳燈。 風一更,雪一更,聒...
    小主正紅閱讀 191評論 0 0