一、前言

大家在处理maven依赖时,肯定都有遇到过包冲突的问题,其中最常见的就是在多级依赖时,会同时引入一个jar包的不同版本,导致在运行时出现NoSuchMethodError的错误,那么大家肯定会好奇对于这些情况maven是怎么去选择版本的呢?其中网上挺多文章已经都解密了它的处理方式,我这里先把这些方式抛出来,然后一个个的去验证它们。
当一个项目中出现重复的依赖包时,maven 2.0.9之后的版本会用如下的规则来决定使用哪一个版本的包:

1、最短路径原则
2、声明优先原则
3、同级依赖后加载覆盖先加载

二、分析与验证

准备:创建一个验证工程已经多个验证模块,并根据校验场景来引入依赖关系,其中作为验证对象的testD构建两个不同版本(1.0和2.0)的jar

maven更新依赖命令 maven 依赖版本_不同版本

1、最短路径原则

分析

maven更新依赖命令 maven 依赖版本_java_02


对于服务A直接依赖了服务B和E,其中B和E都直接或间接的引用了D的两个版本1.0和2.0,此时根据最短路径原则,A最终引用的应该是D的2.0版本

验证

按照上图的依赖关系进行模块依赖

maven更新依赖命令 maven 依赖版本_java_03


maven更新依赖命令 maven 依赖版本_java_04


maven更新依赖命令 maven 依赖版本_maven更新依赖命令_05


maven更新依赖命令 maven 依赖版本_maven_06


其中C依赖了D的1.0版本,E依赖了D的2.0版本,通对A执行mvn dependency:tree 命令来分析A的依赖树

maven更新依赖命令 maven 依赖版本_maven更新依赖命令_07


通过依赖树结果来看,最终依赖的是D的2.0版本,所以验证了maven的最短路径原则;

2、声明优先原则

分析

maven更新依赖命令 maven 依赖版本_java_08


A服务依赖C和E,其中C依赖D的1.0版本,E依赖D的2.0版本,其中C已依赖声明在E之前,此时根据声明优先原则,相同的依赖路径,会安装依赖引入的先后顺序进行选择,选择最先引入的版本,所以应该是选择1.0版本;

maven更新依赖命令 maven 依赖版本_java_09


将E和C的依赖顺序交换,此次应该选择的是D的2.0版本

验证

maven更新依赖命令 maven 依赖版本_maven_10

maven更新依赖命令 maven 依赖版本_maven_11


A服务依赖C和E,其中C依赖D的1.0版本,E依赖D的2.0版本,其中C已依赖声明在E之前,通对A执行mvn dependency:tree 命令来分析A的依赖树,最终引入的是D的1.0版本

maven更新依赖命令 maven 依赖版本_不同版本_12


maven更新依赖命令 maven 依赖版本_maven更新依赖命令_13


将E和C的依赖顺序交换,通对A执行mvn dependency:tree 命令来分析A的依赖树,最终引入的是D的2.0版本,所以验证了声明优先原则;

3、同级依赖,后加载覆盖先加载

maven更新依赖命令 maven 依赖版本_不同版本_14


A直接依赖D的1.0和2.0版本,1.0的依赖声明顺序早于2.0版本,此时2.0版本会覆盖1.0版本从而最终选择2.0版本;

maven更新依赖命令 maven 依赖版本_不同版本_15


交换1.0和2.0的依赖声明顺序,2.0早于1.0,此时1.0版本会覆盖2.0版本,从而最终选择2.0版本

验证

maven更新依赖命令 maven 依赖版本_java_16

maven更新依赖命令 maven 依赖版本_java_17


A直接依赖D的1.0和2.0版本,1.0的依赖声明顺序早于2.0版本,通对A执行mvn dependency:tree 命令来分析A的依赖树,最终引入的是D的2.0版本

maven更新依赖命令 maven 依赖版本_不同版本_18


maven更新依赖命令 maven 依赖版本_java_19


交换1.0和2.0的依赖声明顺序,2.0早于1.0,通对A执行mvn dependency:tree 命令来分析A的依赖树,最终引入的是D的1.0版本,从而最终验证了本级依赖中,后加载的依赖会覆盖先加载的依赖;

三、总结

通过上述的说明和验证,最终得出maven对重复依赖的版本处理方式为:

1、最短路径原则:对于多级依赖出现相同jar的不同版本,maven会选择路径最短的依赖;

2、声明优先原则:对于多级依赖出现相同jar的不同版本,并且所经历的路径相同时,maven会选择最先声明的依赖版本;

3、同级依赖,后声明会覆盖先声明原则:对于同一级的依赖出现相同jar的不同版本,maven会根据依赖声明的先后顺序,选择后声明的依赖版本;