Java以編程方式實現(xiàn)JAR文件的創(chuàng)建
大家好,我是指北君。
在這篇文章中,我們將介紹一下以編程方式創(chuàng)建jar文件的過程。在編寫軟件時,最終我們需要將其部署到生產(chǎn)狀態(tài)。在某些情況下,使用帶有獨立文件的classpath是可以的。通常情況下,處理一個文件會更方便。在Java的情況下,標(biāo)準(zhǔn)的方法是使用JAR、WAR或EAR文件。
基本過程是編寫清單,打開jar,添加內(nèi)容,最后保存jar。
Jar文件的解剖
jar文件是ZIP文件格式的擴(kuò)展,包含了一個清單文件。清單文件是JAR文件專用的特殊文件,可能包含各種設(shè)置。其中一些是主類、可選數(shù)據(jù)(即作者、版本等)和代碼簽名信息。
我們可以使用兼容zip的工具來查看和提取部分或全部存檔。我們還可以包括一個jars或libs子目錄,用于包含依賴性jar。由于jar是zip文件的擴(kuò)展,我們可以包括任何文件或目錄。
創(chuàng)建一個 JarTool 類
為了簡化創(chuàng)建JAR文件的過程,我們創(chuàng)建了一個單獨的、普通的舊Java對象(POJO)類,它封裝了我們的操作。我們可以將條目放入清單文件,創(chuàng)建JAR文件,添加文件或目錄。
我們還可以創(chuàng)建方法來執(zhí)行從JAR中刪除,甚至向現(xiàn)有的JAR追加條目,盡管這些操作需要完全讀取和重寫JAR。
JAR描述符
為了創(chuàng)建一個JAR文件,我們必須首先開始制定清單。
public?class?JarTool?{???? ????private?Manifest?manifest?=?new?Manifest(); ????public?void?startManifest()?{ ????????manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION,?"1.0"); ????} }
如果我們希望jar是可執(zhí)行的,我們必須設(shè)置主類。
public?void?setMainClass(String?mainFQCN)?{ ????if?(mainFQCN?!=?null?&&?!mainFQCN.equals(""))?{ ????????manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS,?mainFQCN); ????} }
另外,如果我們想指定額外的屬性,我們可以把它們添加到清單中,比如說。
addToManifest("Can-Redefine-Classes",?"true");
下面是這個方法。
public?void?addToManifest(String?key,?String?value)?{ ?????manifest.getMainAttributes().put(new?Attributes.Name(key),?value); }
打開JAR文件進(jìn)行編寫
隨著清單的完成,我們現(xiàn)在可以把條目寫到JAR文件中。要做到這一點,我們必須首先打開JAR。
public?JarOutputStream?openJar(String?jarFile)?throws?IOException?{???????? ????return?new?JarOutputStream(new?FileOutputStream(jarFile),?manifest); }
將文件添加到JAR中
在向JAR中添加文件時,Java使用Solaris風(fēng)格的文件名,使用正斜杠作為分隔符(/)。注意,我們可以添加任何類型的文件,包括其他JAR文件或空目錄。這對于包括依賴關(guān)系來說真的很方便。
另外,因為JAR文件是classpath的一種形式,我們必須指定我們希望在JAR中使用絕對路徑的哪一部分。對于我們的目的,根路徑將是我們項目的classpath。
了解了這一點,我們現(xiàn)在可以用這個方法完成我們的JarTool類。
public?void?addFile(JarOutputStream?target,?String?rootPath,?String?source)? ??throws?FileNotFoundException,?IOException?{ ????String?remaining?=?""; ????if?(rootPath.endsWith(File.separator))?{ ????????remaining?=?source.substring(rootPath.length()); ????}?else?{ ????????remaining?=?source.substring(rootPath.length()?+?1); ????} ????String?name?=?remaining.replace("\\","/"); ????JarEntry?entry?=?new?JarEntry(name); ????entry.setTime(new?File(source).lastModified()); ????target.putNextEntry(entry); ???? ????BufferedInputStream?in?=?new?BufferedInputStream(new?FileInputStream(source)); ????byte[]?buffer?=?new?byte[1024]; ????while?(true)?{ ????????int?count?=?in.read(buffer); ????????if?(count?==?-1)?{ ????????????break; ????????} ????????target.write(buffer,?0,?count); ????} ????target.closeEntry(); ????in.close(); }
一個工作實例
為了證明可執(zhí)行jar的最低要求,我們將編寫一個應(yīng)用類,然后看看它是如何工作的。
public?class?Driver?{ ????public?static?void?main(String[]?args)?throws?IOException?{ ????????JarTool?tool?=?new?JarTool(); ????????tool.startManifest(); ????????tool.addToManifest("Main-Class",?"com.javanorth.createjar.HelloWorld"); ????????JarOutputStream?target?=?tool.openJar("HelloWorld.jar"); ???????? ????????tool.addFile(target,?System.getProperty("user.dir")?+?"\\src\\main\\java", ??????????System.getProperty("user.dir")?+?"\\src\\main\\java\\com\\javanorth\\createjar\\HelloWorld.class"); ????????target.close(); ????} }
HelloWorld類是一個非常簡單的類,只有一個main()方法可以打印出文本。
public?class?HelloWorld?{ ????public?static?void?main(String[]?args)?{ ????????System.out.println("Hello?World!"); ????} }
為了證明它的作用,我們有這個例子。
$ javac -cp src/main/java src/main/java/com/javanorth/createjar/HelloWorld.java
$ javac -cp src/main/java src/main/java/com/javanorth/createjar/JarTool.java
$ javac -cp src/main/java src/main/java/com/javanorth/createjar/Driver.java
$ java -cp src/main/java com/javanorth/createjar/Driver
$ java -jar HelloWorld.jar
Hello World!
在這里,我們已經(jīng)編譯了每個類,然后執(zhí)行了Driver類,這將創(chuàng)建HelloWorld jar。最后,我們執(zhí)行了這個jar,結(jié)果是打印出了 "Hello World "信息。
上面的命令應(yīng)該從項目所在地執(zhí)行。
總結(jié)
在本教程中,我們看到了如何以編程方式創(chuàng)建一個jar文件,向其中添加文件,并最終執(zhí)行。
到此這篇關(guān)于Java以編程方式實現(xiàn)JAR文件的創(chuàng)建的文章就介紹到這了,更多相關(guān)Java創(chuàng)建JAR文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
分析java并發(fā)中的wait notify notifyAll
一個線程修改一個對象的值,而另一個線程則感知到了變化,然后進(jìn)行相應(yīng)的操作,這就是wait()、notify()和notifyAll()方法的本質(zhì)。本文將詳細(xì)來介紹它們概念實現(xiàn)以及區(qū)別2021-06-06Java上傳文件錯誤java.lang.NoSuchMethodException的解決辦法
今天小編就為大家分享一篇關(guān)于Java上傳文件錯誤java.lang.NoSuchMethodException的解決辦法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01feign 調(diào)用第三方服務(wù)中部分特殊符號未轉(zhuǎn)義問題
這篇文章主要介紹了feign 調(diào)用第三方服務(wù)中部分特殊符號未轉(zhuǎn)義問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03HttpClient實現(xiàn)遠(yuǎn)程調(diào)用
這篇文章主要為大家詳細(xì)介紹了HttpClient實現(xiàn)遠(yuǎn)程調(diào)用的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08Java實現(xiàn)excel表格轉(zhuǎn)成json的方法
本篇文章主要介紹了Java實現(xiàn)excel表格轉(zhuǎn)成json的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09Java設(shè)計模式之狀態(tài)模式(State模式)介紹
這篇文章主要介紹了Java設(shè)計模式之狀態(tài)模式(State模式)介紹,本文講解了何時使用狀態(tài)模式、如何使用狀態(tài)模式等內(nèi)容,需要的朋友可以參考下2015-03-03