原文:
https://my.oschina.net/u/2377110/blog/1585553
網上有一些 maven-shade-plugin 替代 maven-assembly-plugin 的文章,原因是代 maven-assembly-plugin 打出的 jar 包中要麼是不能設置 Main-Class,要麼 spring 的 META-INF/spring.*文件相互覆蓋了。對於這兩個問題,maven-assembly-plugin 在當前的版本(3.1.0)中都可以解決了(方法見https://my.oschina.net/u/2377110/blog/1584205)。
實際上這兩個插件所針對的用途其實是有差異的,而它們與 maven 默認的 maven-jar-plugin 都是打包插件,簡單的區別如下:
plugin | function |
---|---|
maven-jar-plugin | maven 默認打包插件,用來創建 project jar |
maven-shade-plugin | 用來打可執行包,包含依賴,以及對依賴進行取捨過濾 |
maven-assembly-plugin | 支持定製化打包方式,更多是對項目目錄的重新組裝 |
當你只想將項目打成一個可執行包時,maven-shade-plugin 非常適合。一般情況下,pom 文件中 shade 插件配置如下。
<build>
<plugins>
<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>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.lcifn.Application</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
shade 插件綁定的是 package 生命週期目標,並設置 com.lcifn.Application 爲 Main-Class,以及將 META-INF/spring.*文件合併(追加而非覆蓋),並過濾掉所有依賴的 META/INF 中 SF,DSA,RSA 後綴文件。這裏涉及到 filter 配置和 transformer 配置。
filters 和 artifactSet
Filter 操作在打包時將 jar 包中的內容排除。它是以 groupId:artifactId 爲標識,在 filter 內部可以使用<include>/<exclude>更細緻地控制,既可以移除代碼文件,也可以移除配置文件。
<!-- 按package過濾junit包 -->
<configuration>
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/framework/**</include>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/experimental/**</exclude>
<exclude>org/junit/runners/**</exclude>
</excludes>
</filter>
</filters>
</configuration>
如果想將整個 jar 包都過濾掉,可以使用<artifactSet>,也是指定 groupId:artifactId 的標識。
<configuration>
<artifactSet>
<excludes>
<exclude>classworlds:classworlds</exclude>
<exclude>junit:junit</exclude>
<exclude>jmock:*</exclude>
<exclude>*:xml-apis</exclude>
<exclude>org.apache.maven:lib:tests</exclude>
<exclude>log4j:log4j:jar:</exclude>
</excludes>
</artifactSet>
</configuration>
另外配置<minimizeJar>將項目中沒有使用的依賴自動移除
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
<minimizeJar>可以和<filters>共同使用
<configuration>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>log4j:log4j</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
資源轉換
在打包時,存在將多個構件中的 class 文件或資源文件聚合的需求。shade 插件提供了豐富的 Transformer 工具類。這裏介紹一些常用的 Transformer。
ManifestResourceTransformer
往 MANIFEST 文件中寫入 Main-Class 是可執行包的必要條件。ManifestResourceTransformer 可以輕鬆實現。
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.lcifn.Application</mainClass>
</transformer>
</transformers>
</configuration>
AppendingTransformer
用來處理多個 jar 包中存在重名的配置文件的合併,尤其是 spring。
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
</configuration>
ServicesResourceTransformer
JDK 的服務發現機制是基於 META-INF/services/目錄的,如果同一接口存在多個實現需要合併 ,則可以使用此 Transformer。
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
更多的 Transformer 見http://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html
原始構件與 shade 構件
默認情況下,shade 插件會覆蓋基於項目的 jar 包,而生成包含所有依賴的 jar 包。但有時需要原始的 jar 包和 shade 後的 jar 包同時被部署,可以配置如下。
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<!-- 名稱會作爲後綴在shade構件jar包後 -->
<shadedClassifierName>jackofall</shadedClassifierName>
</configuration>
參考:
http://maven.apache.org/plugins/maven-shade-plugin/index.html
http://www.jianshu.com/p/14bcb17b99e0