common-resource-sdk 工程
依賴: nacos-client
依賴: http-client:4.5.3
bdp-business-data-integration-service 工程
依賴: common-resource-sdk
依賴: elasticsearch-rest-client
依賴: http-client:4.5.10
在bdp-business-data-integration-service
工程中排除了common-resource
的http-client
包,但其打出的JAR包中依舊含有http-client:4.5.3
。
為何排包失敗了呢?
本質原因:
common-resurce
打包方式是jar-with-dependencies
maven-shade-plugin
Apache Maven : maven-shade-plugin
This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies.(該外掛提供了將工件打包到uber jar中的功能,包括其依賴項,並對一些依賴項的包進行著色(即重新命名)。)
The Shade Plugin has a single goal: (Shade外掛只有一個目標:)
shade:shade is bound to the package phase and is used to create a shaded jar. (shade:shade繫結到封裝階段,用於建立一個shaded jar。)
maven-plugin-shade 外掛提供了2個能力:
把整個專案(包含它的依賴)都打包到一個 「uber-jar」 中 shade - 即重新命名某些依賴的包。也由此引出了兩個問題:
+ 什麼是 uber-jar ?
+ 這中打包後帶依賴的 Jar 包一般稱為uber-jar
或fat-jar
或者jar-with-dependencies
;意思就是包含依賴的 jar。
+ 什麼是 shade ?
+ shade 意為遮擋,在此處可理解為:對依賴的 jar 包的重定向(主要通過重新命名的方式)。
shade
n. 燈罩;陰涼處;(樹)蔭;色度;痕跡,影子,遺風;一點;差別;背陰;暗部;陰魂;濃淡深淺
vt. 給…遮擋(光線);畫陰影;加燈罩;把…塗暗;險勝
uber
adj.超級的;極其的;最好的;
If you like to use minimizeJar this means you have to use JDK8+. This is based on a required upgrade of dependencies.
如果你喜歡使用minimizeJar,這意味著你必須使用JDK8+。這是基於所需的依賴項升級。
Latest version(最新版本) = 3.5.0
https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-shade-plugin
Official Document/官方檔案
General instructions on how to use the Shade Plugin can be found on the usage page. Some more specific use cases are described in the examples given below.
有關如何使用Shade外掛的一般說明可以在使用頁面上找到。下面給出的範例中描述了一些更具體的用例。
In case you still have questions regarding the plugin's usage, please feel free to contact the user mailing list. The posts to the mailing list are archived and could already contain the answer to your question as part of an older thread. Hence, it is also worth browsing/searching the mail archive.
如果您對外掛的使用仍有疑問,請隨時聯絡使用者郵寄清單。郵寄清單中的貼文已存檔,可能已經包含了您問題的答案,作為舊執行緒的一部分。因此,瀏覽/搜尋郵件檔案也是值得的。
If you feel like the plugin is missing a feature or has a defect, you can fill a feature request or bug report in our issue tracker. When creating a new issue, please provide a comprehensive description of your concern. Especially for fixing bugs it is crucial that the developers can reproduce your problem. For this reason, entire debug logs, POMs or most preferably little demo projects attached to the issue are very much appreciated. Of course, patches are welcome, too. Contributors can check out the project from our source repository and will find supplementary information in the guide to helping with Maven.
如果你覺得外掛缺少功能或有缺陷,你可以在我們的問題跟蹤器中填寫功能請求或錯誤報告。建立新問題時,請對您關心的問題進行全面描述。特別是對於修復錯誤,開發人員能夠重現您的問題是至關重要的。出於這個原因,非常感謝整個偵錯紀錄檔、POM,或者最好是附加到該問題的小演示專案。當然,修補程式也是受歡迎的。參與者可以從我們的原始碼庫中檢視該專案,並在幫助使用Maven的指南中找到補充資訊。
也就是說,當執行
mvn package
時會自動觸發shade
。
maven-shade-plugin
,只需要在 pom.xml
的 <plugins>
標籤下新增它的設定即可,範例如下:<project>
//...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<configuration>
<!-- 此處按需編寫更具體的設定 -->
</configuration>
<executions>
<execution>
<!-- 和 package 階段繫結 -->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
// ...
</project>
預設情況下,會把專案所有的依賴都包含進最終的 jar 包中。當然,我們也可在 <configuration>
標籤內設定更具體的規則。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--
<parent>
<artifactId>johnny-webapp-quickstart</artifactId>
<groupId>cn.johnnyzen</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
-->
<modelVersion>4.0.0</modelVersion>
<version>1.0.0-SNAPSHOT</version>
<groupId>cn.johnnyzen</groupId>
<artifactId>study-maven</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven-shade-plugin.version>3.5.0</maven-shade-plugin.version>
<fastjson.version>2.0.3</fastjson.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<configuration>
<!-- 此處按需編寫更具體的設定 -->
</configuration>
<executions>
<execution>
<!-- 和 package 階段繫結 -->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
mvn clean install
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--
<parent>
<artifactId>johnny-webapp-quickstart</artifactId>
<groupId>cn.johnnyzen</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
-->
<modelVersion>4.0.0</modelVersion>
<version>1.0.0-SNAPSHOT</version>
<groupId>cn.johnnyzen</groupId>
<artifactId>study-maven</artifactId>
<properties>
<java.jdk.version>1.8</java.jdk.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven-shade-plugin.version>3.5.0</maven-shade-plugin.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<fastjson.version>2.0.3</fastjson.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.jdk.version}</source>
<target>${java.jdk.version}</target>
<!--<encoding>${project.build.outputEncoding}</encoding>-->
<!-- <skipTests>true</skipTests> --><!-- 跳過測試 -->
<!--<verbose>true</verbose>--> <!--<showWarnings>true</showWarnings>--> <!--<fork>true</fork>--><!-- 要使compilerVersion標籤生效,還需要將fork設為true,用於明確表示編譯版本設定的可用 -->
<!--<executable>--><!-- path-to-javac --><!--</executable>--><!-- 使用指定的javac命令,例如:<executable>${JAVA_1_4_HOME}/bin/javac</executable> -->
<!--<compilerVersion>${java.version}</compilerVersion>--><!-- 指定外掛將使用的編譯器的版本 -->
<!--<meminitial>128m</meminitial>--><!-- 編譯器使用的初始記憶體 -->
<!--<maxmem>512m</maxmem>--><!-- 編譯器使用的最大記憶體 -->
<!--<compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument>--><!-- 這個選項用來傳遞編譯器自身不包含但是卻支援的引數選項 -->
</configuration>
</plugin>
</plugins>
</build>
</project>
mvn clean install
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--
<parent>
<artifactId>johnny-webapp-quickstart</artifactId>
<groupId>cn.johnnyzen</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
-->
<modelVersion>4.0.0</modelVersion>
<version>1.0.0-SNAPSHOT</version>
<groupId>cn.johnnyzen</groupId>
<artifactId>study-maven</artifactId>
<properties>
<java.jdk.version>1.8</java.jdk.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven-shade-plugin.version>3.5.0</maven-shade-plugin.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<fastjson.version>2.0.3</fastjson.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies>
<build>
</build>
</project>
mvn clean install
include/exclude
2 種操作'*
' 、'?'
groupId:artifactId[[:type]:classfier]
<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>
<filters>
結合 <includes>
& <excludes>
標籤可實現更靈活的依賴選擇。<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>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
如果最終的 jar 包被其他的專案所依賴的話,直接地參照此 jar 包中的類可能會導致類載入衝突,這是因為 classpath 中可能存在重複的 class 檔案。為了解決這個問題,我們可以使用 shade 提供的重定位功能,把部分類移動到一個全新的包中。範例如下:
<configuration>
<relocations>
<relocation>
<pattern>org.codehaus.plexus.util</pattern>
<shadedPattern>org.shaded.plexus.util</shadedPattern>
<excludes>
<exclude>org.codehaus.plexus.util.xml.Xpp3Dom</exclude>
<exclude>org.codehaus.plexus.util.xml.pull.*</exclude>
</excludes>
</relocation>
</relocations>
</configuration>
涉及標籤:
<pattern>:原始包名
<shadedPattern>:重新命名後的包名
<excludes>:原始包內不需要重定位的類,類名支援萬用字元
例如,在上述範例中,我們把 org.codehaus.plexus.util 包內的所有子包及 class 檔案(除了 ~.xml.Xpp3Dom 和 ~.xml.pull 包下的所有 class 檔案)重定位到了 org.shaded.plexus.util 包內。
當然,如果包內的大部分類我們都不需要,一個個排除就顯得很繁瑣了。
此時我們也可以使用 <includes>
標籤來指定我們僅需要的類,範例如下:
<project>
...
<relocation>
<pattern>org.codehaus.plexus.util</pattern>
<shadedPattern>org.shaded.plexus.util</shadedPattern>
<includes>
<include>org.codehaud.plexus.util.io.*</include>
</includes>
</relocation>
...
</project>
<mainClass>
啟動類就可以了。<project>
...
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.sonatype.haven.HavenCli</mainClass>
</transformer>
</transformers>
</configuration>
...
</project>
熟悉 jar 包的朋友們都知道,jar 包中預設會包含一個 MANIFEST.MF 檔案,裡面描述了一些 jar 包的資訊。
使用 java 自帶的 jar 命令打包的時候可以指定 MANIFEST.MF,其中也可以指定 Main-Class 來使得 jar 包可執行。
那麼使用 shade 來指定和直接在 MANIFEST.MF 檔案中指定有什麼區別呢?
答案是沒有區別,細心的讀者會發現 <mainClass>
標籤的父標籤是 <transformer>
有一個 implementation 屬性,其值為 「~.ManifestResourceTransformer」,意思是 Manifest 資原始檔轉換器。
上述範例只自指定了啟動類,因此 shade 會為我們自動生成一個包含 Main-Class 的 MANIFEST.MF 檔案,然後在打 jar 包時指定這個檔案。
那如果我們想要完全客製化 MANIFEST.MF 檔案內容怎麼辦呢?我們可以使用 <manifestEntries>
標籤,範例如下:
<project>
...
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>org.sonatype.haven.ExodusCli</Main-Class>
<Build-Number>123</Build-Number>
</manifestEntries>
</transformer>
</transformers>
</configuration>
...
</project>
可執行jar包通過 java -jar
命令啟動
專案中涉及到的依賴可能會有它們所必需的資原始檔,使用 shade 可以把它們聚合在同一個 jar 包中。
預設地,shade 為我們提供了 12 個 ResourceTransformer 類:
類名 | 作用 |
---|---|
ApacheLicenseResourceTransformer | 防止 LICENSE 檔案重複 |
ApacheNoticeResourceTransformer | 準備合併的 NOTICE |
AppendingTransformer | 為某個資原始檔附加內容 |
ComponentsXmlResourceTransformer | 聚合 Plexus components.xml |
DontIncludeResourceTransformer | 防止包含指定的資源 |
GroovyResourceTransformer | 合併 Apache Groovy 的擴充套件模組 |
IncludeResourceTransformer | 新增專案中的檔案為資原始檔 |
ManifestResourceTransformer | 自定義 MANIFEST 檔案 |
PluginXmlResourceTransformer | 聚合 Maven 的 plugin.xml 設定 |
ResourceBundleAppendingTransformer | 合併 ResourceBundles |
ServicesResourceTransformer | 重定位且合併 META-INF/services 資原始檔中的 class 檔案 |
XmlAppendingTransformer | 為 XML 資原始檔附加內容 |
如果上述 12 個類都不能夠滿足我們的需求,我們可以實現 shade 提供的介面,按需自定義一個 ResourceTransformer,實現方法詳見官網 Using your own Shader implementation。