【Maven笔记】Maven依赖分析及冲突解决

在项目开发过程中, 常会需要分析JAR包依赖的需要, 从而解决 JAR 冲突等问题

Maven 常见分析命令

查看全部JAR信息

# 列出项目的所有JAR包
mvn dependency:list 
# 列出项目的所有JAR包依赖树
mvn dependency:tree
# 列出项目的所有JAR包依赖树, 仅显示指定JAR的节点
## 参数形式: [groupId]:[artifactId]:[type]:[version]
## 多个JAR包可用逗号分割
## 示例是分析org.slf4j相关JAR, 博主解决UDF与自编译HIVE环境冲突时使用的
mvn dependency:tree -Dverbose -Dincludes=org.slf4j:*
# 列出项目的所有JAR包依赖树, 排除指定JAR的节点
mvn dependency:tree -Dverbose -Dexcludes=org.slf4j:*

上述两个命令是查看JAR包较为常用的命令, 如下是进阶参数

  • -Dverbose: 会把被忽略的JAR, 即相同JAR包的不同版本引入也列出来.

查看依赖使用分析

# -Dverbose: 会把声明且使用JAR包也显示出来
mvn dependency:analyze-only

命令主要分析如下情况的依赖使用情况

  • 声明了并且使用了的依赖
  • 没有声明但是使用了的依赖
  • 声明了但是没有使用的依赖

分析多模块依赖信息

mvn dependency:analyze-duplicate

用于分析 <dependencies/><dependencyManagement/> 中重复声明的依赖, 两者区别见dependencyManagement与dependencies区别

列出所有的远程repositories

mvn dependency:list-repositories

清理本地repository

# 分析项目依赖, 然后删除本地缓存, 重新从远程进行下载
mvn dependency:purge-local-repository
# 跳过删除前下载动作
## 由于需要对全部依赖进行处理, 会首先下载直至全部依赖就绪, 再进行删除缓存
mvn dependency:purge-local-repository -DactTransitively=false
# 包含/排除指定依赖
mvn dependency:purge-local-repository -Dincludes=org.slf4j:slf4j-api,org.slf4j:log4j-over-slf4j
# 自定义清理
## -DmanualInclude: 可以清理不在本项目中的依赖, 不会重新解析依赖, 因为本项目不需要这些依赖. 
## 这个对清理parent pom, 导入的pom, maven插件非常有用
mvn dependency:purge-local-repository -DmanualIncludes=org.apache:apache

如何解决冲突问题

利用scope使用阶段

scope 类型:

  • compile: 默认情况, 表示为当前依赖参与项目的编译、测试和运行阶段,属于强依赖.打包之时,会达到包里去.
  • test: 该依赖仅参与测试相关的内容,包括测试用例的编译和执行,比如定性的Junit.
  • runtime: 该依赖仅参与运行周期中的使用.一般这种类库都是接口与实现相分离的类库,比如JDBC类库,在编译之时仅依赖相关的接口,在具体的运行之时,才需要具体的mysql、oracle等等数据的驱动程序.此类的驱动都是为runtime的类库.
  • provided: 该依赖在打包过程中,不需要打进去,这个由运行的环境来提供,比如tomcat或者基础类库等等,事实上,该依赖可以参与编译、测试和运行等周期,与 compile 等同.区别在于打包阶段进行了 exclude 操作.
  • system: 使用上与 provided 相同,不同之处在于该依赖不从 maven 仓库中提取,而是从本地文件系统中提取,其会参照 systemPath 的属性进行提取依赖.
  • import: 这个是 maven 2.0.9版本后出的属性,import 只能在 dependencyManagement 的中使用,能解决 maven单继承问题,import依赖关系实际上并不参与限制依赖关系的传递性.

该方法主要用于处理运行环境与包冲突, 而非包内部的JAR冲突

 <!-- 仅用于测试阶段 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.6.1</version>
    <scope>test</scope>
</dependency>

 <!-- 不编译进包,利用hive运行环境的hive-exec -->
<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-exec</artifactId>
    <version>${hive.version}</version>
    <scope>provided</scope>
</dependency>

利用 <exclusions/>`

如下为 Hadoop 与 hive 的 org.slf4j 发生冲突会报错, 利用如下命令进行显式排除

注意: 博主利用 * 通配符进行排除失败, 读者可使用自行用依赖树进行分析是否奏效

<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-exec</artifactId>
    <version>1.2.1</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>3.2.1</version>
</dependency>

预防包与运行环境的冲突情况

如果在大公司, UDF包等运行的环境相对固定, 而且其大数据平台一般均为自编译的, 具备着较强限制, 如何设置从而预防包冲突可以采用 maven-enforcer-plugin 插件(官网链接).

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>3.0.0-M3</version>
    <executions>
        <execution>
            <id>enforce-versions</id>
            <goals>
                <goal>enforce</goal>
            </goals>
            <configuration>
                <rules>
                    <requireMavenVersion>
                        <version>3.6.1</version>
                    </requireMavenVersion>
                    <requireJavaVersion>
                        <version>1.8.0</version>
                    </requireJavaVersion>
                    <bannedDependencies>
                        <!--是否检查传递性依赖(间接依赖)-->
                        <searchTransitive>true</searchTransitive>
                        <excludes>
                            <exclude>com.google.guava:guava</exclude>
                            <exclude>org.slf4j:*</exclude>
                        </excludes>
                        <message>Prompt for error message</message>
                    </bannedDependencies>
                </rules>
            </configuration>
        </execution>
    </executions>
</plugin>

参考资料

  1. maven的mvn dependency依赖分析和常用命令介绍
  2. maven-enforcer-plugin
  3. dependencyManagement与dependencies区别

【Maven笔记】Maven依赖分析及冲突解决
https://www.windism.cn/2209565849.html
作者
windism
发布于
2021年6月24日
许可协议