1. 程式人生 > >使用 maven 外掛 maven-shade-plugin 對可執行 java 工程及其全部依賴 jar 進行打包

使用 maven 外掛 maven-shade-plugin 對可執行 java 工程及其全部依賴 jar 進行打包

現在基本上都是採用 maven 來進行開發管理,我有一個需求是需要把通過 maven 管理的 java 工程打成可執行的 jar 包,這樣也就是說必需把工程依賴的 jar 包也一起打包。而使用 maven 預設的 package 命令構建的 jar 包中只包括了工程自身的 class 檔案,並沒有包括依賴的 jar 包。我們可以通過配置外掛來對工程進行打包,pom 具體配置如下:

maven-assembly-plugin (使用此外掛會有一些問題)

Xml程式碼  收藏程式碼
  1. <plugin>  
  2.     <artifactId>maven-assembly-plugin</
    artifactId>  
  3.     <configuration>  
  4.         <appendAssemblyId>false</appendAssemblyId>  
  5.         <descriptorRefs>  
  6.             <descriptorRef>jar-with-dependencies</descriptorRef>  
  7.         </descriptorRefs>  
  8.         <archive>  
  9.             <manifest
    >  
  10.                 <mainClass>com.chenzhou.examples.Main</mainClass>  
  11.             </manifest>  
  12.         </archive>  
  13.     </configuration>  
  14.     <executions>  
  15.         <execution>  
  16.             <id>make-assembly</id>  
  17.             <phase>package</
    phase>  
  18.             <goals>  
  19.                 <goal>assembly</goal>  
  20.             </goals>  
  21.         </execution>  
  22.     </executions>  
  23. </plugin>  

其中 <mainClass></mainClass> 的值表示此工程的入口類,也就是包含 main 方法的類,在我的例子中就是 com.chenzhou.examples.Main。配置完 pom 後可以通過執行 mvn assembly:assembly 命令來啟動外掛進行構建。構建成功後會生成 jar 包,這樣我們就可以在命令列中通過 java -jar XXX.jar 來執行 jar 檔案了。 

不過使用此外掛會有一些問題:我在工程中依賴了 spring 框架的 jar 包,我打包成功後使用命令來呼叫 jar 包時報錯如下(內網環境):

Shell程式碼  收藏程式碼
  1. org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'http://www.springframework.org/schema/beans/spring-beans-3.0.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.  

關於此問題報錯的原因,我在網上找到一篇文章對此有比較詳細的解釋:http://blog.csdn.net/bluishglc/article/details/7596118 簡單來說就是 spring 在啟動時會載入 xsd 檔案,它首先會到本地查詢 xsd 檔案(一般都會包含在 spring 的 jar 包中),如果找不到則會到 xml 頭部定義的 url 指定路徑下中去尋找 xsd,如果找不到則會報錯。

附:在 spring jar 包下的 META-INF 資料夾中都會包含一個 spring.schemas 檔案,其中就包含了對 xsd 檔案的路徑定義,具體如下圖所示:

spring-aop.jar包下META-INF資料夾下的內容

圖:spring-aop.jar 包下 META-INF 資料夾下的內容

spring.schemas檔案內容

圖:spring.schemas 檔案內容

由於我的工程是在內網,所以通過 url 路徑去尋找肯定是找不到的,但是比較奇怪的是既然 spring 的 jar 包中都會包含,那為什麼還是找不到呢?

該 bug 產生的原因如下:工程一般依賴了很多的 jar 包,而被依賴的 jar 又會依賴其他的 jar 包,這樣,當工程中依賴到不同的版本的 spring 時,在使用 assembly 進行打包時,只能將某一個版本 jar 包下的 spring.schemas 檔案放入最終打出的jar包裡,這就有可能遺漏了一些版本的 xsd 的本地對映,所以會報錯。

所以一般推薦使用另外的一個外掛來進行打包,外掛名稱為:maven-shade-plugin,shade 外掛打包時在對 spring.schemas 檔案處理上,它能夠將所有 jar 裡的 spring.schemas 檔案進行合併,在最終生成的單一 jar 包裡,spring.schemas 包含了所有出現過的版本的集合,要使用 shade 外掛,必須在 pom 進行如下配置:

Xml程式碼  收藏程式碼
  1. <plugin>  
  2.     <groupId>org.apache.maven.plugins</groupId>  
  3.     <artifactId>maven-shade-plugin</artifactId>  
  4.     <version>1.4</version>  
  5.     <executions>  
  6.         <execution>  
  7.             <phase>package</phase>  
  8.             <goals>  
  9.                 <goal>shade</goal>  
  10.             </goals>  
  11.             <configuration>  
  12.                 <transformers>  
  13.                     <transformer  
  14.                         implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  15.                         <resource>META-INF/spring.handlers</resource>  
  16.                     </transformer>
  17.                     <transformer  
  18.                         implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">  
  19.                         <mainClass>com.chenzhou.examples.Main</mainClass>  
  20.                     </transformer>  
  21.                     <transformer  
  22.                         implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  23.                         <resource>META-INF/spring.schemas</resource>  
  24.                     </transformer>  
  25.                 </transformers>  
  26.             </configuration>  
  27.         </execution>  
  28.     </executions>  
  29. </plugin>  

上面配置檔案中有一段定義:

  1. <transformer  
  2.     implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  3.     <resource>META-INF/spring.handlers</resource>  
  4. </transformer>  
  5. <transformer  
  6.    implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  7.    <resource>META-INF/spring.schemas</resource> 
  8. </transformer>

上面這段配置意思是把 spring.handlers 和 spring.schemas 檔案以 append 方式加入到構建的 jar 包中,這樣就不會出現 xsd 找不到的情況。

配置完 pom 後,呼叫 mvn clean install 命令進行構建,構建成功後開啟工程 target 目錄,發現生成了 2 個 jar 包,一個為:original-XXX-0.0.1-SNAPSHOT.jar,另一個為:XXX-0.0.1-SNAPSHOT.jar,其中 original...jar 裡只包含了工程自己的 class 檔案,而另外的一個 jar 包則包含了工程本身以及所有依賴的 jar 包的 class 檔案。我們只需要使用第二個 jar 包就可以了。

參考資料: