解決專案版本衝突——maven-shade外掛使用
文章目錄
背景
當我們在maven專案中引入第三方元件時,三方元件中的依賴可能會與專案已有元件發生衝突。
比如三方元件中依賴httpclient的版本是4.5.x,而專案中已有的httpclient版本是3.1.x,那麼此時就會產生一下兩種情況:
- 如果用三方元件的高版本httpclient覆蓋原有的低版本httpclient,有可能會導致原來專案啟動執行失敗。即使高版本相容低版本,也不能允許開發人員有這樣高風險的操作
- 如果在三方maven依賴中對其對依賴的httpclient在引入時使用進行排除,使三方元件使用專案中的低版本httpclient,此時可能會因為版本不一致導致三方元件無法使用
在這樣的情況下我們應當如何保證不影響專案原有依賴版本的情況下正常使用三方元件呢?此時可以考慮使用maven-shade-plugin外掛
maven-shade-plugin介紹
maven-shade-plugin在maven官方網站中提供的一個外掛,官方文件中定義其功能如下:
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.
簡單來說就是將依賴的包在package階段一起打入jar包中,以及對依賴的jar包進行重新命名從而達到隔離的作用。這裡為了解決上面的問題我們主要使用第二個功能特性,使得相同依賴不同版本達到共存的目的。
解決問題
1.環境準備
這裡用fastjson來模擬使用maven-shade-plugin解決專案中不同版本共存問題。原專案此時使用的是1.1.15版本的fastjson
<!-- 原專案 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</ artifactId>
<version>1.1.15</version>
</dependency>
假引入一個三方依賴,該依賴使用1.2.75版本的fastjson
<!-- 將引入依賴 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
2.解決方案
搭建一個新的模組rename-dependencies,專門用於存放1.2.75依賴。在pom檔案中新增1.2.75的依賴,然後新增maven-shade-plugin外掛。rename-dependencies的pom如下
<?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">
<groupId>com.sk</groupId>
<artifactId>rename-dependencies</artifactId>
<version>1.0-SNAPSHOT</version>
<modelVersion>4.0.0</modelVersion>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.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>
<relocations>
<relocation>
<pattern>com.alibaba</pattern>
<shadedPattern>shade.com.alibaba</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
從配置檔案中可以看到,由於maven-shade-plugin外掛在解決這個問題上其實是通過對依賴進行重新命名而達到隔離的目的,所以配置主要是集中在relocations中。這裡將以com.alibaba開頭的包全部重新命名為以shade.com.alibaba開頭。
3.引入依賴
將rename-dependencies進行打包,打包好之後在原專案中引入rename-dependencies的依賴。此時在引入rename-dependencies之後,可以在專案下看到該依賴中的fastjson包名發生了變化
此時在程式碼中呼叫fastjson相關方法,會提示選擇所需要包,如下圖,此時問題解決,兩個版本的fastjson可同時使用已經相容。
一些需要注意的坑
-
描述: 引入依賴找不到重新命名的shade包
-
原因:重新命名的模組和需要引入依賴的模組在一個專案中,idea優先找本專案,所以沒有走倉庫
-
解決方案:
- 將模組從專案maven中移除,右鍵專案-maven-unlink maven projects
- 新建一個專案專門來做依賴
maven-shade-plugins的其他使用
- 打入和排除指定jar包。maven-shade-plugins還有個功能就是打入和排除指定的jar包,通過和指定。
官方配置事例
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<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>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
官方配置事例
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<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>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
- 排除包內資源。在上面的pom中使用maven-shade-plugin時,使用來對包內META-INF下的一些資源進行排除。如上面的配置中排除META-INF下的資原始檔
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>