Maven 直接依赖、间接依赖、依赖冲突、依赖仲裁

2023-09-21 14:51:34

直接依赖和间接依赖


在项目中直接引入的依赖叫做直接依赖,而那些被动引入的就叫间接依赖

直接依赖和间接依赖

比如上图中,A 是我们的项目,我们在项目中直接引入了 B 模块,所以 B 和 A 的关系就是直接依赖,而 B 工程内部引入了 C,
所以 B 和 C 也是直接依赖关系,如果 B 工程在引入 C 时,指定了 C 模块的依赖范围是 <scope>compile</scope>,那么 C 模
块就会随着 B 模块一同被引入到我们的工程A 中,这时候 A 和 C 的关系就是间接依赖


依赖冲突

Maven 的依赖冲突,我认为有两种情况,Maven 能自动解决的、需要手动解决的

1. Maven 可以自动解决的依赖冲突

在项目中,不管是直接依赖还是间接依赖,当有多个 <groupId><artifactId>相同,<version> 不同的依赖引入时,
Maven 就会认为我们引入了相同模块的不同版本,其就会被判定为依赖冲突,这种情况 Maven 会用自己的仲裁机制帮
我们取舍


2. 需要手动解决的依赖冲突

模块间的 <groupId><artifactId><version> 都不相同,但是引入的这些模块中具有相同路径的类(包名+类名
完全相同),这个时候就需要我们自己去解决依赖冲突问题


Maven 的依赖仲裁

依赖仲裁是 Maven 自动解决依赖冲突的手段,我们想更好的利用它,就必须知道其仲裁的规则,其通过 最短路径优先
先声明优先 两个依据来判断最终留下的模块


最短路径优先

当项目的依赖树中存在相同模块的不同版本时,Maven 的仲裁机制就会介入,其首先会通过最短路径的方式来对
冲突的模块进行取舍,如下图,假设我们的项目是A,明显C模块发生了依赖冲突,那么按照最短路径优先的原则,
Maven 最后会留下 A → B → C 1.0 这个路径下的 C 模块

最短路径优先

先声明优先

当两个依赖冲突的模块,其路径距离相同时,就会使用先声明优先的规则,这个就很简单了,就是留下先声明的模块,
如下图,假设我们的项目是A,两个冲突的模块C到 A 的距离是相同的,这时 Maven 就会根据先声明优先的规则选择
A → B → C 1.0 这个路径下的 C 模块,因为其声明在前

先声明优先

至于什么叫先声明,非常简单,用上图例子,我写个伪代码

<!-- 这个 B 的依赖信息就是先声明的,所以仲裁后会留下B模块中依赖的C模块 -->
<dependency>
    <groupId>B</groupId>
    <artifactId>B</artifactId>
    <version>release</version>
</dependency>
<dependency>
    <groupId>D</groupId>
    <artifactId>D</artifactId>
    <version>release</version>
</dependency>

了解仲裁规则后,也可以利用 Maven 的仲裁规则,保留自己想要的模块,比如上面例子中,我们想保留模块 C 2.0,
那么就可以将模块 C 2.0 的依赖信息主动声明在依赖列表的最前面,这样不论是最短路径规则还是先声明的规则,都会
判定 C 2.0 被保留,伪代码如下:

<!--在依赖列表的最前面主动声明模块C2.0的依赖信息-->
<dependency>
    <groupId>C</groupId>
    <artifactId>C</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>B</groupId>
    <artifactId>B</artifactId>
    <version>release</version>
</dependency>
<dependency>
    <groupId>D</groupId>
    <artifactId>D</artifactId>
    <version>release</version>
</dependency>

手动解决依赖冲突


需要手动解决的情况,是指不同模块中,具有相同路径的类(包名和类名完全相同),从而导致项目启动后,类加载器加载了
同名的非目标类,从而出现 ClassNotFoundExceptionNoClassDefFoundErrorLinkageError 等类似的错误

手动解决依赖冲突,首先需要找出路径相同的类所在的模块,其次决定要留用的模块

找出类路径相同的模块

可以借助 Maven 的生命周期插件 maven-enforcer-plugin

1. 在项目的 Pom.xml 中添加配置

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>1.4.1</version>
            <executions>
                <execution>
                    <id>enforce-dependencies</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>display-info</goal>
                        <goal>enforce</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>extra-enforcer-rules</artifactId>
                    <version>1.0-beta-4</version>
                </dependency>
            </dependencies>
            <configuration>
                <rules>
                    <banDuplicateClasses>
                        <findAllDuplicates>true</findAllDuplicates>
                    </banDuplicateClasses>
                </rules>
            </configuration>
        </plugin>
    </plugins>
</build>

(2) 执行 mvn clean package enforcer:enforce 命令后,就能看见重复的类和模块

找到类重复的模块

(3) 找到冲突的模块后,删掉弃用的模块,如果是直接依赖的模块直接删除依赖信息就好,
如果是间接依赖的模块,就要使用 <exclusions> 排除依赖传递,方式如下:

<dependency>
    <groupId></groupId>
    <artifactId></artifactId>
    <version></version>
    <!-- 排除依赖传递 -->
    <exclusions>
        <exclusion>
            <groupId>要弃用的模块的groupId</groupId>
            <artifactId>要弃用的模块的artifactId</artifactId>
        </exclusion>
    </exclusions>
</dependency>
更多推荐

Keepalived 高可用(附带配置实例,联动Nginx和LVS)

Keepalived一、Keepalived相关知识点概述1.1单服务的风险(单点故障问题)1.2一个合格的集群应该具备的特性1.3VRRP虚拟路由冗余协议1.4健康检查1.5”脑裂“现象二、Keepalived2.1Keepalived是什么?2.2Keepalived体系主要模块及其作用2.3Keepalived工

Git --- 基础介绍

Git---基础介绍git是什么git---工作区,暂存区,资源库git---文件状态git---branch和HEADgit---一次正常的git提交流程git是什么Git是一款分布式源代码管理工具(版本控制工具)Git和其他传统版本控制系统比较:传统的版本控制系统(例如SVN)是基于差异的版本控制,它们存储的是一组

HSRP(热备份路由选择协议)的概念,原理与配置实验

作者:Insist--个人主页:insist--个人主页梦想从未散场,传奇永不落幕,持续更新优质网络知识、Python知识、Linux知识以及各种小技巧,愿你我共同在CSDN进步目录一、了解HSRP协议1.什么是HSRP协议2、HSRP协议的作用二、HSRP组成员1.活跃路由器2.备份路由器3.虚拟路由器4.其他三、H

Java——String类

一、String类String是引用类型,在Java中“”引起来的也是String类型对象。//打印"hello"字符串(String对象)的长度System.out.println("hello".length());内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:publicsta

Linux【一】

目录一、Linux操作系统发展历史UnixMinixLinux二、Linux简介Linux是什么Linux的版本Linux内核版本Linux发行版本Linux应用领域?Linux注意事项三、Linux目录系统目录用户目录文件颜色四、Linux命令行基本操作Linux命令格式:查看帮助文档tab键自动补全命令输入历史命令

Nacos源码启动报错:protoc did not exit cleanly. Review output for more information.

报错解析:这是一个关于Protobuf(ProtocolBuffers)编译器出现问题的错误信息。Protobuf是一种用于结构化数据序列化的工具,该错误提示表明Protobuf编译器在执行过程中出现了问题,并建议检查输出以获取更多信息。快速解决:启动Nacos源码出现这个这报错,到这bean没有被创建,可以使用ide

边界框回归的魔法:揭秘精准高效的MPDIoU损失函数

文章目录摘要1、简介2、相关工作2.1、目标检测和实例分割2.2.场景文本识别2.3、边界框回归的损失函数3、点距最小的并集交点4、实验结果4.1、实验设置4.2、数据集4.3、评估协议4.4、目标检测的实验结果4.5、字符级场景文本识别的实验结果4.6、实例分割的实验结果5、结论摘要https://arxiv.org

分享一下微信拼团活动制作步骤是什么

微信拼团活动是一种非常受欢迎的营销手段,可以帮助商家吸引更多的消费者,提高销售额和品牌知名度。下面我将为大家详细介绍如何制作微信拼团活动。一、了解拼团活动特点和优势拼团活动是一种以社交网络为依托的营销方式,通过将商品以团购的形式推送给消费者,让消费者通过拼团的方式购买商品,享受团购优惠。拼团活动的特点和优势如下:参与门

机器学习实战:Python基于LASSO回归进行正则化(十二)

文章目录1前言1.1LASSO的介绍1.2LASSO的应用2.diabetes数据集实战演示2.1导入函数2.2导入数据2.3拟合模型(AIC/BIC)2.4AIC/BIC可视化2.5拟合交叉验证模型及可视化3.Hitters数据集实战演示3.1导入函数3.2导入数据3.3数据预处理3.4定义变量和缩放数据3.5拟合模

python基础05 循环 变量 函数组合案例

目录1.前言:2.案例详情:->2.1案例拆解--->2.1.1主页功能:--->2.1.2查余额:--->2.1.3存钱--->2.1.4取钱--->2.1.5返回首页重试[可有可无]--->2.1.6退出3.实现代码(python版)4.运行结果:->4.1文字式想写的可以直接复制文字->4.2图示(更清晰)5.总

【Linux】编译器 gcc/g++

1、背景知识(1)[LMY@hecs-38755~]$gcccode.c-ocode.exe-std=c99【-o生成指定名字的可执行文件,-std=c99以C99的标准执行程序】(2)安装g++,yuminstallgcc-c++2、gcc如何完成(1)预处理(进行宏替换)预处理功能主要包括展开头文件,宏替换,文件包

热文推荐