实际上手体验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之前声明的情况;
<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,明白啦!
作者:京东科技 宋慧超
来源:京东云开发者社区
实际上手体验maven面对冲突Jar包的加载规则的更多相关文章
- java运行jar包时候加载指定目录的其他jar支持包
最近发生一个小故障,调试好的项目,发布成jar包后无法找到oracle的驱动,研究了一下解决了.记录一下. 写了一个run.sh脚本 #!/bin/bash cd ~ cd app nohup jav ...
- springboot运行jar包时候加载指定目录的其他jar支持包
最近发生一个小故障,调试好的项目,发布成jar包后无法找到oracle的驱动,研究了一下解决了.记录一下.写了一个run.sh脚本 #!/bin/bash cd ~ cd app nohup java ...
- 如何更新maven需要的jar包
第一次使用maven,检出项目生成时出现缺少xxx.jar,目录在C盘下: 拿mybatis-spring-1.2.2.jar来说,发现在C:\Users\Administrator\.m2\repo ...
- [JAVA/Maven/IDEA]解决JAR包冲突
1 前言 想必这个问题,诸多同仁都遇到过. 很不凑巧,这段时间咱也屡次撞上这问题好几次了. 因此,实在是有必要说说怎么解决好这问题了0.0 2 诊断:包冲突的异常信息特征 [类定义未发现错误] NoC ...
- (十)maven之排除冲突jar包
排除冲突jar包 jar包冲突 <dependencies> <dependency> <groupId>org.springframework</group ...
- idea提示,格式化代码,清除不使用的包快捷键,maven自动导jar包
一.提示快捷键 idea默认快捷键是ctrl+space,通常和别的软件快捷键冲突,所以将快捷键修改为alt+/ 二.格式化快捷键ctrl+alt+l,通常和qq.tim快捷键冲突,请修改qq或者ti ...
- 实测Maven上传jar包到私服的方法归纳
Hello,各位小伙伴大家好,我是小栈君.好久不见,最近因为工作的缘故,导致了更新变慢,但是小栈君也在积极的做素材的规划,毕竟学习知识点的归纳和提炼需要一定的时间. 所以还请大家多多见谅,下一期的分享 ...
- Maven工程引入jar包
Maven项目引入jar包的方法 法一.手动导入:项目右键—>Build Path—>Configure Build Path—>选中Libraries—>点击Add Exte ...
- maven本地安装jar包同时生成pom文件
maven 本地安装jar包:mvn install:install-file -Dfile=本地路径/ojdbc12.jar -DgroupId=com.oracle -DartifactId=oj ...
- 如何在maven中添加jar包
Maven 中央仓库地址: 1. http://www.sonatype.org/nexus/ 2. http://mvnrepository.com/ (本人推荐仓库) 3. http://repo ...
随机推荐
- cesium源码编译调试及调用全过程
完整记录一次cesium源码从下载.打包.调用.调试的全过程. 本文使用软件或API版本: VSCode Node:12.18.3 cesium版本:1.94 总体步骤: 下载源码 执行npm ins ...
- 基于RL(Q-Learning)的迷宫寻路算法
强化学习是一种机器学习方法,旨在通过智能体在与环境交互的过程中不断优化其行动策略来实现特定目标.与其他机器学习方法不同,强化学习涉及到智能体对环境的观测.选择行动并接收奖励或惩罚.因此,强化学习适用于 ...
- Typora 最新中文版安装破解V1.4.8
Typora中文破解版是一款好用极简免费的跨平台Markdown编辑器,软件使用这款软件能够帮助用户轻松将文本转换到HTML,软件从底层向上设计,软件支持markdown的标准语法,同时这款软件还支持 ...
- TOF和结构光
文章目录 TOF和结构光 一.ToF 二.结构光 三.测量距离.分辨率.开发周期的对比 TOF和结构光 一.ToF ToF(Time of Flight)飞行时间 字面理解就是通过光的飞行时间来计算距 ...
- .net 6 使用 NEST 查询,时间字段传值踩坑
0x01业务描述 说明: 同事搭建的业务系统,最开始使用 log4net 记录到本地日志. 然后多个项目为了日志统一,全部记录在 Elasticsearch ,使用 log4net.Elastic ...
- google + chatgpt
google注册 网址:https://www.google.com/ 使用右上角登录按钮 点击创建账户然后根据步骤注册 chagpt注册 1.https://chat.openai.com/auth ...
- 扯什么kafka顺序消费,然后呢?古尔丹,代价是什么
著名面试八股文之kafka为什么读写效率高,写的答案之一是partition顺序写,因而能保证分区内的不连续的有序性. 这里的重点是有序追加到磁盘,而不是严格意义上的完全有序性. 几年前参加了一大数据 ...
- 2020-09-25:rust中Point是结构体类型,【let p1=Point{x:25,y:25};let p2=p1;】请问p1和p2是同一个对象吗?
福哥答案2020-09-25:#福大大架构师每日一题# 不是同一个对象.p1和p2直接存内容,不存地址.这点跟java里的new对象是不一样的.p1.x和p1的地址相同,说明p1存的是内容,而不是地址 ...
- 2022-08-11:以下go语言代码输出什么?A:panic;B:编译错误;C:json marshal 报错;D:null;E:nil。 package main import ( “e
2022-08-11:以下go语言代码输出什么?A:panic:B:编译错误:C:json marshal 报错:D:null:E:nil. package main import ( "e ...
- 2021-08-02:按公因数计算最大组件大小。给定一个由不同正整数的组成的非空数组 A,考虑下面的图:有 A.length 个节点,按从 A[0] 到 A[A.length - 1] 标记;只有当
2021-08-02:按公因数计算最大组件大小.给定一个由不同正整数的组成的非空数组 A,考虑下面的图:有 A.length 个节点,按从 A[0] 到 A[A.length - 1] 标记:只有当 ...