打包是一个比较头疼的事情,默认 Maven 打包的结果只包含项目本身的代码,如果要执行代码,还得带上依赖。maven-shade-plugin插件就能够帮我们把项目依赖的包也打进最终文件。
在现代 Java 开发中,Maven 项目打包是一个比较头疼的事情,我们经常需要处理项目的依赖管理和打包问题。
在 Maven 项目中引入第三方组件时,这些三方组件的依赖可能与项目已有的依赖发生冲突。例如,如果第三方组件依赖的 HttpClient 版本是 4.5.x,而项目中已有的 HttpClient 版本是 3.1.x,就会产生以下两种情况:
用高版本覆盖低版本:如果使用第三方组件的高版本 HttpClient 覆盖项目中的低版本 HttpClient,有可能导致项目启动或运行失败。即使高版本兼容低版本,这种高风险的操作也是不被允许的;
排除高版本依赖:如果在第三方 Maven 依赖中排除了高版本的 HttpClient,使其使用项目中的低版本 HttpClient,可能会因为版本不一致导致第三方组件无法正常使用。
在这样的情况下,我们如何保证在不影响项目原有依赖版本的前提下,正常使用第三方组件呢?这时可以考虑使用 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 包进行重命名从而达到隔离的作用。这里为了解决上面的问题我们主要使用第二个功能特性,使得相同依赖不同版本达到共存的目的。
这里以 fastjson 库为例,模拟使用 maven-shade-pluginn 解决项目中不同版本共存的问题。假设原项目使用的是 1.1.15 版本的 fastjson:
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.1.15version>
dependency>
并引入一个第三方依赖,该依赖使用 1.2.75 版本的 fastjson:
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.75version>
dependency>
搭建一个新的模块 rename-dependencies,专门用于存放 1.2.75 版本的 fastjson 依赖。在 pom.xml 文件中添加该依赖,并配置 maven-shade-plugin:
<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.examplegroupId>
<artifactId>rename-dependenciesartifactId>
<version>1.0-SNAPSHOTversion>
<modelVersion>4.0.0modelVersion>
<dependencies>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.75version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-shade-pluginartifactId>
<version>3.2.4version>
<executions>
<execution>
<phase>packagephase>
<goals>
<goal>shadegoal>
goals>
<configuration>
<filters>
<filter>
<artifact>*:*artifact>
<excludes>
<exclude>META-INF/*.SFexclude>
<exclude>META-INF/*.DSAexclude>
<exclude>META-INF/*.RSAexclude>
excludes>
filter>
filters>
<relocations>
<relocation>
<pattern>com.alibabapattern>
<shadedPattern>shade.com.alibabashadedPattern>
relocation>
relocations>
configuration>
execution>
executions>
plugin>
plugins>
build>
project>
配置文件中的 relocations 部分通过重命名包名来隔离依赖。在这个例子中,将以 com.alibaba 开头的包名重命名为 shade.com.alibaba。
将 rename-dependencies 模块打包后,在原项目中引入:
<dependency>
<groupId>com.examplegroupId>
<artifactId>rename-dependenciesartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
引入后,项目中的 fastjson 包名将会被重命名,确保不同版本可以共存。
在实际操作中,可能会遇到引入依赖后找不到重命名的包的问题。此时,可以通过以下方法解决:
除了包重命名外,maven-shade-plugin 还支持打入和排除指定的 JAR 包及资源文件。例如:
<filters>
<filter>
<artifact>*:*artifact>
<excludes>
<exclude>META-INF/*.SFexclude>
<exclude>META-INF/*.DSAexclude>
<exclude>META-INF/*.RSAexclude>
excludes>
filter>
filters>
通过这种方式,可以进一步控制打包过程中的细节,满足不同的需求。