1. 程式人生 > 其它 >淺談 java 中構建可執行 jar 包的幾種方式

淺談 java 中構建可執行 jar 包的幾種方式

        有時候,由於專案的需要,我們會將原始碼編譯後以工具包(class打成jar包)的形式對外提供,此時, 你的 jar 包不一定要是可執行的,只要能通過編譯,能被別人以 import 的方式呼叫就行了。但還有的 情況是,我們的 jar 包是要可執行的,即能直接在 cmd 下直接執行。前者的打包很簡單,在 eclipse 中, 直接選中要打包的 java 檔案和其它資源、依賴檔案, export → Java → JAR file 即可。需要注意的是, 這種方式匯出的 jar 包是不可執行的,比如你執行如下的語句: java -jar test.jar java -classpath test.jar com.test_maven.App 會直接報錯:無法找到主類或者找不到 xxx 依賴包/類,這是由於你沒有定義 MANIFEST.MF 資源描述檔案所致, 或者你直接把依賴的 jar 包打進了你最終的 jar,而這種巢狀的依賴 jar 包是不能直接被程式 import 識別的。         下面我們看看如何在 eclipse 中構建一個可執行的 jar 包。

(1)最簡單的還是依賴於 eclipse 的匯出功能:

export → java → Runnable JAR file,這種形式的匯出

可以通過 lanuch configuration 指定一個 MainClass,並會自動生成 MANIFEST.MF ,而且會幫你把依賴的 jar 包解壓出來,一併打進最終

的 jar 包,這樣就能被你的程式碼 import 引用了。

(2)上述方法是 eclipse 自帶的,eclipse 也有個專門的外掛叫做 Fat Jar,支援許多定製化的功能,

具體請參見下面的連結。但是這個外掛有些缺陷,比如修改原始碼後如果你不 clean & rebuild project,

 它會使用快取重新打包,這樣你的編譯程式碼還是老的,會造成執行錯誤,而且這樣是十分不方便的。

用Fat Jar Eclipse Plug-In打包可執行jar檔案

http://8366.iteye.com/blog/480652

(3)稍微大點的專案都會用 maven 或者 ant 來構建,在 maven 工程中,我們也可以很方便的打包成可執行的 jar 包。預設Maven生成的JAR包只包含了編譯生成的.class檔案和專案資原始檔,而要得到一個可以直接在命令列通過 java命令執行的JAR檔案,還要滿足兩個條件:

  • JAR包中的/META-INF/MANIFEST.MF元資料檔案必須包含Main-Class資訊。
  • 專案所有的依賴都必須在Classpath中,其可以通過 MANIFEST.MF 指定或者隱式設定。

Maven有好幾個外掛能幫助使用者完成上述任務,不過用起來最方便的還是maven-shade-plugin,它可以讓使用者配置 Main-Class的值,然後在打包的時候將值填入/META-INF/MANIFEST.MF檔案。關於專案的依賴,它很聰明地將依賴 JAR檔案全部解壓後,再將得到的.class檔案連同當前專案的.class檔案一起合併到最終的CLI包中,這樣,在執行CLI JAR檔案的時候,所有需要的類就都在Classpath中了。下面是一個配置樣例:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>1.4</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
              <mainClass>com.juvenxu.mavenbook.HelloWorldCli</mainClass>
            </transformer>
          </transformers>
        </configuration>
      </execution>
    </executions>
  </plugin>

上述例子中的,我的Main-Class是com.juvenxu.mavenbook.HelloWorldCli,構建完成後,對應於一個常規的 hello-world-1.0.jar檔案,我還得到了一個hello-world-1.0-cli.jar檔案。細心的讀者可能已經注意到了,這裡用的 是cli這個classifier。最後,我可以通過java -jar hello-world-1.0-cli.jar命令執行程式。當然了,如果你需要更加自由 的打包方式,那就用 maven-assembly-plugin 吧。它支援各種打包檔案格式,包括zip、tar.gz、tar.bz2等等,通過一個打包 描述檔案(例如 src/main/assembly.xml),它能夠幫助使用者選擇具體打包哪些檔案集合、依賴、模組、和甚至本地倉庫檔案,

每個項的具體打包路徑使用者也能自由控制。比如下面的配置通過設定 assembly 檔案的配置節點 dependencySets/includes,來實現 maven build 生成的 jar 包只包含指定的 jar 依賴。 

<assembly ... ooxx>
	<fileSets>
	</fileSets>
	<dependencySets>
        <dependencySet>
        	<unpack>false</unpack> 
            <outputDirectory>lib</outputDirectory>
            <scope>runtime</scope>
		    <includes>  
		        <include>groupId:artifactId</include>  
		    </includes>
        </dependencySet>
    </dependencySets>
</assembly>

具體請參見: Maven實戰(九)——打包的技巧

http://www.infoq.com/cn/news/2011/06/xxb-maven-9-package

maven釋出 jar型別的工程

http://mengyunshuitian.iteye.com/blog/1759864

maven assembly plugin dependencySet with transitive dependencies

http://stackoverflow.com/questions/22505886/maven-assembly-plugin-dependencyset-with-transitive-dependencies

http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html#dependencySet

(4)可以使用兩個 Maven 外掛幫助您完成:maven-jar-plugin 和 maven-dependency-plugin。 maven-jar-plugin 可以做很多事情,但在這裡,我們只對使用它來修改預設 MANIFEST.MF 檔案的內容感興趣。 在您的 POM 檔案的外掛部分新增清單 1 所示程式碼: 清單 1. 使用 maven-jar-plugin 修改 MANIFEST.MF

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>com.mypackage.MyClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

所有 Maven 外掛通過一個 <configuration> 元素公佈了其配置,在本例中,maven-jar-plugin 修改它的 archive 屬性, 特別是存檔檔案的 manifest 屬性,它控制 MANIFEST.MF 檔案的內容。包括 3 個元素: addClassPath:將該元素設定為 true 告知 maven-jar-plugin 新增一個 Class-Path 元素到 MANIFEST.MF 檔案,以及在  Class-Path 元素中包括所有依賴項。 classpathPrefix:如果您計劃在同一目錄下包含有您的所有依賴項,作為您將構建的 JAR,那麼您可以忽略它;否則使用  classpathPrefix 來指定所有依賴 JAR 檔案的字首。在清單 1 中,classpathPrefix 指出,相對存檔檔案,所有的依賴項 應該位於 “lib” 資料夾。 mainClass:當用戶使用 lib 命令執行 JAR 檔案時,使用該元素定義將要執行的類名。 當您使用這 3 個元素配置好了 MANIFEST.MF 檔案之後,下一步是將所有的依賴項複製到 lib 資料夾。為此,使用  maven-dependency-plugin,如清單 2 所示: 清單 2. 使用 maven-dependency-plugin 將依賴項複製到庫

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy</id>
            <phase>install</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>
                  ${project.build.directory}/lib
                </outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

maven-dependency-plugin 有一個 copy-dependencies,目標是將您的依賴項複製到您所選擇的目錄。本例中,我將依賴項複製到  build 目錄下的 lib 目錄(project-home/target/lib)。 將您的依賴項和修改的 MANIFEST.MF 放在適當的位置後,您就可以用一個簡單的命令啟動應用程式: java -jar jarfilename.jar 更多技巧,您可以參考:

關於 Apache Maven 您不知道的 5 件事

http://www.ibm.com/developerworks/cn/java/j-5things13/

(5)當然了,如果你不怕麻煩的話,手動打包,自己建立、維護 MANIFEST.MF 檔案也是可以的,你可以參考如下連結:

http://blog.csdn.net/mango_song/article/details/8531389

http://gushuizerotoone.iteye.com/blog/1757002

(6)把包釋出到 nexus

專案上右鍵 → run as → maven build

附:Maven的座標GAV(groupId, artifactId, version)定義

pom定義了最小的maven元素,允許groupId,artifactId,version。在 POM 中,groupId, artifactId, packaging, version 叫作 maven 座標,它能唯一的確定一個專案。有了 maven 座標,我們就可以用它來指定我們的專案所依賴的其他專案,外掛,或者父專案。一般 maven 座標寫成如下的格式: groupId:artifactId:packaging:version

  • groupId: 專案或者組織的唯一標誌,並且配置時生成的路徑也是由此生成,如org.codehaus.mojo生成的相對路徑為:/org/codehaus/mojo
  • artifactId: 專案的通用名稱
  • version: 專案的版本
  • packaging: 打包的機制,如pom, jar, maven-plugin, ejb, war, ear, rar, par
  • classifier: 分類,它表示在相同版本下針對不同的環境或者jdk使用的jar,如果配置了這個元素,則會將這個元素名在加在最後來查詢相應的jar,例如:
<dependency>  
                <groupId>net.sf.json-lib</groupId>   
                <artifactId>json-lib</artifactId>   
                <version>2.2.2</version>  
                <classifier>jdk15</classifier>    
            </dependency>

這樣配置即可找到json-lib-2.2.2-jdk15.jar ,其他的就不解釋了,應該明白他的用途了吧。 POM關係:

主要為依賴,繼承,合成

REF:

使用maven外掛對java工程進行打包

http://chenzhou123520.iteye.com/blog/1706242

關於如何從jar包中讀取配置、屬性檔案,請參考:

http://my.oschina.net/leejun2005/blog/95186

Apache Maven 入門篇(下)

http://www.oracle.com/technetwork/cn/community/java/apache-maven-getting-started-2-405568-zhs.html

maven 配置篇 之pom.xml(一)

http://zyl.iteye.com/blog/41754

Maven最佳實踐:劃分模組

http://juvenshun.iteye.com/blog/305865

在Eclipse中建立Maven多模組工程的例子

http://www.blogways.net/blog/2013/05/13/maven-multi-modules-demo.html