jar包打包實現
jar包打包可以使用jar指令實現打包,在命令行中輸入jar可以查看jar指令的內容
從最後顯示的兩個示例看出存在兩種打包的方法,兩者的區別就是是否使用自己定義的MANIFEST清單文件。第一個示例沒有使用MANIFEST文件進行打包,所以最終生成的jar包中MANIFEST文件爲默認文件,這種方式適用於比較簡單的jar包結構,不存在其他jar包依賴以及生成的jar包不需要可執行。這種方式生成的jar包不能使用
java -jar XXX.jar
命令執行,因爲MANIFEST文件中未指定程序入口。而第二個實例是比較常用的打包方式,即是使用自定義的MANIFEST文件參與打包,這樣能夠實現往包中添加依賴,並且可以指定程序入口,實現java -jar XXX.jar
直接運行jar包。
第一種簡單的打包方式
最簡單的就是在當前文件夾下將編譯的class字節碼文件進行打包輸出。示例如下:
編寫三個java文件,test1.java test2.java 以及Main.java
public class test1
{
public static void main(String[] args)
{
}
public void display()
{
System.out.println("this is class test1");
}
}
以及test2.java 文件
public class test2
{
public static void main(String[] args)
{
}
public void display()
{
System.out.println("this is class test2");
}
}
Main.java
public class Main
{
public static void main(String[] args)
{
for(String a:args)
{
System.out.println("給定的參數"+a);
}
test1 t1 = new test1();
t1.display();
test2 t2 = new test2();
t2.display();
}
}
命令行下將這三個文件進行編譯,使用javac命令實現編譯。
用jar指令將編譯的class文件打包
打包過程中有顯示已添加清單。用解壓工具打開生成的
test.jar
包,可以看到如下的結構: 除了編譯的三個class文件外多了一個META-INF文件夾,裏面有一個MANIFEST.MF(清單文件)的文件,這個文件的作用非常重要,後面說明。我們先看它裏面的內容
非常簡單的清單,只包含清單版本與java版本。
這個時候執行
java -jar test.jar
有如下效果: 沒有主清單屬性報錯。這是因爲我們使用第一種方法生成jar使用了默認的清單,默認清單沒有指定程序入口,所以出錯。
可以直接更改jar包中的MANIFEST文件(解壓工具打開,更改後保存),改成如下效果:
再一次執行
java -jar test.jar
後程序輸入正確內容: 在MANIFEST文件中添加了Main-Class屬性指定了程序入口,實現了直接執行jar文件。
所以說使用默認的MANIFEST是不能直接執行jar文件,要麼使用自己定義的MANIFEST文件打包,要麼更改包中的MANIFEST文件。
第二種打包方式
第二種打包方式更加通用,一般情況下java文件第一行都是package XXX;
即是包名,也決定了編譯後的class文件存在的路徑。當有多個java文件要編譯打包並且他們存在不同的包名時,如果還是按照第一種方法打包時一個文件一個文件的寫非常不現實,所以有了第二種方法。將所有要打包的class文件存在的目錄以及依賴的jar包全部放在一個根文件夾裏面(比如是foo),然後編寫MANIFEST清單文件,指定程序入口以及其他添加的依賴的jar包。在執行指令:
注意 上面的指令中
foo/
文件夾後面有一個空格還有一個點 下面看一個例子
同樣還是test1.java與test2.java以及Main.java 但是各自有自己的包名。
package cn.mytest1;
public class test1
{
public static void main(String[] args)
{
}
public void display()
{
System.out.println("this is class test1");
}
}
package cn.mytest2;
public class test2
{
public static void main(String[] args)
{
}
public void display()
{
System.out.println("this is class test2");
}
}
package cn.mymain;
import cn.mytest1.test1;
import cn.mytest2.test2;
public class Main
{
public static void main(String[] args)
{
for(String item:args)
{
System.out.println("傳遞參數"+item);
}
test1 t1 = new test1();
test2 t2 = new test2();
t1.display();
t2.display();
}
}
同樣使用javac 指令編譯,三個class文件存在於不同的路徑下,因爲他們包名不一樣。把編譯號的含有class文件的文件夾全部放在foo文件夾下:
然後在foo 外面寫一個MANIFEST文件:
MANIFEST內容如下:
注意:MANIFEST 文件最後一行是空行。
命令行下執行指令:
jar cvfm test.jar MANIFEST.MF -C foo/ .
在命令行下測試jar包是否能夠直接運行了,使用指令
java -jar test.jar
正確打包,成功運行jar.
MANIFEST文件介紹
通過上面的兩個例子,可以看到MANIFEST文件對於jar打包都是必須的。MANIFEST文件描述了打包後的jar文件的詳細信息,存在於打包後的META-INF 的文件夾.一個簡單的MANIFEST文件主要內容如下:
主要就是Manifest-Version Main-Class Class-Path這三個屬性在製作jar包時非常重要.Manifest-Version 是版本號,照着寫就行。Main-Class則是jar包的入口程序,指定運行的類的全稱(一定要包含包名),這樣可以使用
java -jar name.jar
直接運行jar包。第三個Class-Path是指的打包時需要依賴的其他jar包,打包的時候自己的程序中也可能含有其他的jar包所以要添加依賴。 注意每個MANIFEST屬性冒號與內容之間都有一個空格,並且寫完後最後還要留有一行空行,不然運行時還是出現找不到主清單屬性的錯誤
小結
jar文件打包容易出錯的地方就是Manifest清單文件的編寫,容易出一些格式上的錯誤比如屬性的冒號和內容之間少空格,Class-Path中添加依賴之間沒有空格,依賴文件過多,多行書寫的時候每行開頭沒加空格,文件最後一行沒有空行等等。寫MANIFEST文件的時候注意這些關鍵的地方就不會在打包上面耗費太多的時間。