ToB企服应用市场:ToB评测及商务社交产业平台
标题:
实际上手体验maven面对冲突Jar包的加载规则
[打印本页]
作者:
欢乐狗
时间:
2023-7-19 11:22
标题:
实际上手体验maven面对冲突Jar包的加载规则
一、
问题背景
相信大家在日常的开发过程中都遇到过Jar包冲突的问题,emm,在最近处理业务需求时我也遇到了不同版本jar包冲突导致项目加载出错的问题。主要是一个完整的项目会不可避免的使用第三方的Jar包来实现功能开发,各种第三方包之间可能会存在依赖关系,不同版本的依赖就会可能导致依赖间的相互冲突,进而导致整个项目加载的失败。
这篇文章主要记录了本次遇到的问题:即maven在面对不同版本的jar包在pom文件中同时声明会存在加载覆盖的问题,于是通过查询网上相关资料对maven包的加载规则介绍,并通过实际场景对其进行分析验证;
二、
maven加载原则
1.最短路径原则:面对多级(两级及以上)的不同依赖,会优先选择路径最短的依赖;
2.声明优先原则:面对多级(两级及以上)的同级依赖,先声明的依赖会覆盖后声明的依赖;
3.同级依赖中,后声明的依赖会覆盖先声明的依赖;
三、
本地验证maven加载原则
1.
最短路径原则
:使用最短路径加载的前提是,项目中存在两级以上的不同依赖jar包,此时项目会优先加载路径最短的jar包;
◦
实例验证:
分别在common模块和service模块中
间接和直接
的引入不同版本的elasticsearch-rest-client,观察项目中面对
不同路径长度
情况下实际加载时所使用的版本情况。
▪
common模块:
在
common
模块中引入
elasticsearch-rest-high-level-client
依赖包, 而该依赖包它引入了
elasticsearch-rest-client 7.4.2,
从而实现在common模块中
间接
引用该包;
common
的pom文件:
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.2</version>
</dependency>
</dependencies>
复制代码
▪
service模块:
为了验证不同路径长度下maven的包加载顺序
,
我们在
service
模块中
直接
引入
elasticsearch-rest-client 6.8.13;
service
的pom文件:
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.8.13</version>
</dependency>
</dependencies>
复制代码
▪
实际加载结果
:在IDEA中加载pom文件时,可以在maven管理中看到已经提示jar包冲突;
▪
mvn dependency:tree
: 我们可以通过mvn dependency :tree命令来查看该项目的依赖树,观察发现实际加载的版本是
elasticsearch-rest-client 6.8.13
,符合maven中的
最短路径优先
原则;
声明优先原则
:声明优先原则的前提是对于两级以上的同级依赖,先声明的依赖会覆盖后声明的依赖包;
◦
实例验证:
针对该原则的验证场景构造
不再关注
模块是否直接或者间接引用不同版本的es,我们在common模块和service模块中都
直接
引用不同版本的es,然后通过
改变
两个模块在pom文件中声明的
先后顺序
来观察项目启动后实际加载的jar包;
▪
common模块
:在common模块中直接引入依赖包elasticsearch-rest-client 7.4.2
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.4.2</version>
</dependency>
</dependencies>
复制代码
▪
service模块
:在service模块中引入依赖包elasticsearch-rest-client 6.8.13
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.8.13</version>
</dependency>
</dependencies>
复制代码
◦
实际加载结果:
▪场景1:我们将common模块在pom文件中
先引入
,然后将在service模块置于common模块
后面引入
,观察项目实际加载情况;
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>backend_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>backend_service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
复制代码
▪观察加载结果图,发现实际加载的是es-rest-client 7.4.2, 即确实是
common模块
的
声明生效
,service模块后声明导致其中的es
未被加载
。符合
声明优先
原则;
◦场景2:我们将service模块在pom文件中
先引入
,然后将在common模块置于service模块
后面引入
,观察项目实际加载情况;;
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>backend_service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>backend_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
复制代码
▪观察项目实际加载结果图,发现实际加载的是
es-rest-client 6.8.13
, 即确实是
模块
的
声明生效
,common模块后声明导致其中的es
未被加载
。发现符合
声明优先
原则;
◦声明优先原则场景
验证结束
;
3. 同级依赖中后加载覆盖先加载原则
;
◦
实例验证:
为了构造在同级依赖中的加载场景
,
我们在项目中直接引入两个不同es版本的依赖,然后同样通过改变两个es版本在pom中的声明顺序来观察项目实际加载的es版本。
▪场景1:我们首先验证client 7.4.2依赖包在client 6.8.13
之前
声明的情况;
org.elasticsearch.client elasticsearch-rest-client 7.4.2 <dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.8.13</version>
</dependency>
</dependencies>
复制代码
▪观察maven的实际加载结果如下,发现项目中实际加载的es-rest-client 版本是6.8.13,先声明的7.4.2版本并未实际加载到项目中。符合
同级依赖中后加载覆盖先加载
原则。
▪场景2:然后我们改变声明顺序,将client 6.8.13依赖包在client 7.4.2
之前
声明;
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.8.13</version>
</dependency>
</dependencies> org.elasticsearch.client elasticsearch-rest-client 7.4.2
复制代码
▪观察maven实际加载结果如下,发现项目中实际加载的es-rest-client 版本是7.4.2,先声明的6.8.13版本并未实际加载到项目中。符合
同级依赖中后加载覆盖先加载
原则。
四、
常见异常
****Jar发生冲突后在程序启动时常见
异常报错,
下面
四种
异常是能够直观表征
Jar包加载冲突
:
◦程序抛出java.lang.ClassNotFoundException异常;
◦程序抛出java.lang.NoSuchMethodError异常;
◦程序抛出java.lang.NoClassDefFoundError异常;
◦程序抛出java.lang.LinkageError异常等;
五、
总结
之前只是浅层的了解maven包的加载,没有结合具体的加载原则进行系统的学习验证,正好通过需求开发中遇到依赖冲突相关问题对maven的加载原则进行探究。ok,明白啦!
作者:京东科技 宋慧超
来源:京东云开发者社区
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4