需求
有時候寫一些庫,需要其它三方依賴,但是又不想這個依賴影響到使用方,可以將這些三方依賴打到自己的專案jar包,並且更換包名,避免衝突(更換包名之後,專案中的類引用第三方依賴的類import語句也會跟著變化)。如Mybatis就使用了Ognl庫,在打包時把Ognl的所有類都打到了Mybatis自己的jar中。
實現
實現的目標主要為兩點
- 核心目標:將所需依賴打進自己的專案jar包
- 次要目標:將所需依賴的原始碼也同步打進自己專案的原始碼中,方便使用者瀏覽原始碼。
要實現這兩個需求需要使用到maven-source-plugin
、maven-jar-plugin
、maven-shade-plugin
。
例子如下:
專案依賴javassist
庫,需要把javassist
庫打進自己專案jar包中,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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wangtao</groupId>
<artifactId>enhanced-thread-local</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 三方依賴 -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.30.2-GA</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<!-- 必須繫結到package階段, 因為shade外掛也是package階段執行 -->
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<!-- 不要將構建的原始碼jar附加到構建產物中,由maven-shade-plugin來做 -->
<attach>false</attach>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>shade-when-package</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<!-- 建立source jar -->
<createSourcesJar>true</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<dependencyReducedPomLocation>
${project.build.directory}/dependency-reduced-pom.xml
</dependencyReducedPomLocation>
<!-- 需要將哪些依賴打進專案jar包中 -->
<artifactSet>
<includes>
<include>org.javassist:javassist</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>org.javassist:javassist</artifact>
<excludes>
<exclude>META-INF/MANIFEST.MF</exclude>
</excludes>
</filter>
</filters>
<relocations>
<!-- 將javassist及其子包打到com.wangtao.etl.agent.javassist包中 -->
<relocation>
<pattern>javassist</pattern>
<shadedPattern>com.wangtao.etl.agent.javassist</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
執行mvn install
命令的工作流程如下(mvn package
同理,只是少了將jar、sources.jar安裝到本地倉庫這一步)
第一步:maven-jar-plugin
先將本專案打成jar包
第二步:maven-source-plugin
將本專案的原始碼打成sources.jar
第三步:maven-shade-plugin
將artifactSet引數項指定的依賴打進專案jar包中,如果有relocations配置,則根據對應配置調整依賴在jar包中的位置,並且改寫import語句。最後替換掉第一步打好的原始jar。
第四步:maven-shade-plugin
將artifactSet引數項指定的依賴原始碼打進專案sources.jar包中,這一步預設是關閉的,需要配置createSourcesJar引數為true,原始碼位置也受relocations配置影響。其中shadeSourcesContent引數用於控制是否改寫原始碼中的import語句,預設也是false。最後替換掉第二步打好的原始sources.jar。
第五步:將jar、sources.jar安裝到本地倉庫中。
注意的點
maven-source-plugin
-
繫結的生命週期需要為
package
,不要設定成verify
。因為maven-shade-plugin
要將maven-source-plugin
生成的專案原始碼包和自己生成的第三方依賴原始碼包合成最終的原始碼包。 -
attach
引數要設定成false,預設為true,否則會有如下警告。引數含義:不要將構建的原始碼jar附加到構建產物中。關閉之後由maven-shade-plugin
來attach。artifact com.wangtao:enhanced-thread-local:java-source:sources:1.0.0 already attached, replace previous instance
-
如果沒有
maven-shade-plugin
外掛,只是把專案原始碼安裝到本地倉庫,則繫結生命週期為verify
、attach
設定成true,是比較好的工程實踐,這樣子mvn package
命令不會觸發生成原始碼包的任務,因為生命週期順序為package->verify->install。install的目標是構建產物,因此需要把attach
設定成true,才會把原始碼包也會安裝到本地倉庫中。
maven-shade-plugin
createSourcesJar
引數需要設定成true,該引數用於控制是否生成第三方依賴的原始碼包,且合併到專案中的原始碼包中。shadeSourcesContent
引數需要設定成true,如果調整了第三方依賴的位置(即包名發生變化),同步調整專案原始碼中引用的第三方依賴類的import語句。dependencyReducedPomLocation
預設為project.basedir/dependency-reduced-pom.xml
,將其調整到target目錄,這樣git提交時會被忽略,一般target目錄肯定是設定了ignore的。- 使用
filter
排除掉第三方依賴的MANIFEST.MF檔案,不然和專案自己的MANIFEST.MF產生衝突。