freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

实际上手体验maven面对冲突Jar包的加载规则
京东云技术团队 2024-08-08 11:14:29 21903

一、问题背景

相信大家在日常的开发过程中都遇到过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中的最短路径优先原则;


2.声明优先原则:声明优先原则的前提是对于两级以上的同级依赖,先声明的依赖会覆盖后声明的依赖包;


实例验证:针对该原则的验证场景构造不再关注模块是否直接或者间接引用不同版本的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之前声明的情况;

<dependencies><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>7.4.2</version></dependency><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><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>7.4.2</version></dependency></dependencies>

观察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,明白啦!

# 数据安全
本文为 京东云技术团队 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
京东云技术团队 LV.10
最懂产业的云
  • 1750 文章数
  • 91 关注者
京东中台化底层支撑框架技术分析及随想
2025-04-08
Web Components实践:如何搭建一个框架无关的AI组件库
2025-04-08
计算机网络协议介绍
2025-04-08
文章目录