实际上手体验maven面对冲突Jar包的加载规则

京东云开发者
• 阅读 291

一、问题背景

相信大家在日常的开发过程中都遇到过Jar包冲突的问题,emm,在最近处理业务需求时我也遇到了不同版本jar包冲突导致项目加载出错的问题。主要是一个完整的项目会不可避免的使用第三方的Jar包来实现功能开发,各种第三方包之间可能会存在依赖关系,不同版本的依赖就会可能导致依赖间的相互冲突,进而导致整个项目加载的失败。

这篇文章主要记录了本次遇到的问题:即maven在面对不同版本的jar包在pom文件中同时声明会存在加载覆盖的问题,于是通过查询网上相关资料对maven包的加载规则介绍,并通过实际场景对其进行分析验证;

实际上手体验maven面对冲突Jar包的加载规则

二、maven加载原则

1.最短路径原则:面对多级(两级及以上)的不同依赖,会优先选择路径最短的依赖;

2.声明优先原则:面对多级(两级及以上)的同级依赖,先声明的依赖会覆盖后声明的依赖;

3.同级依赖中,后声明的依赖会覆盖先声明的依赖;

三、本地验证maven加载原则

1.最短路径原则:使用最短路径加载的前提是,项目中存在两级以上的不同依赖jar包,此时项目会优先加载路径最短的jar包; 实际上手体验maven面对冲突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包冲突;

实际上手体验maven面对冲突Jar包的加载规则

mvn dependency:tree: 我们可以通过mvn dependency :tree命令来查看该项目的依赖树,观察发现实际加载的版本是elasticsearch-rest-client 6.8.13,符合maven中的最短路径优先原则;

实际上手体验maven面对冲突Jar包的加载规则

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

实际上手体验maven面对冲突Jar包的加载规则

实例验证: 针对该原则的验证场景构造不再关注模块是否直接或者间接引用不同版本的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未被加载。符合声明优先原则;

实际上手体验maven面对冲突Jar包的加载规则

◦场景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未被加载。发现符合声明优先原则;

实际上手体验maven面对冲突Jar包的加载规则

◦声明优先原则场景验证结束

3. 同级依赖中后加载覆盖先加载原则

实际上手体验maven面对冲突Jar包的加载规则

实例验证: 为了构造在同级依赖中的加载场景 我们在项目中直接引入两个不同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版本并未实际加载到项目中。符合同级依赖中后加载覆盖先加载原则。

实际上手体验maven面对冲突Jar包的加载规则

▪场景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版本并未实际加载到项目中。符合同级依赖中后加载覆盖先加载原则。

实际上手体验maven面对冲突Jar包的加载规则

四、常见异常

**Jar发生冲突后在程序启动时常见异常报错,** 下面四种异常是能够直观表征Jar包加载冲突

◦程序抛出java.lang.ClassNotFoundException异常;

◦程序抛出java.lang.NoSuchMethodError异常;

◦程序抛出java.lang.NoClassDefFoundError异常;

◦程序抛出java.lang.LinkageError异常等;

五、总结

之前只是浅层的了解maven包的加载,没有结合具体的加载原则进行系统的学习验证,正好通过需求开发中遇到依赖冲突相关问题对maven的加载原则进行探究。ok,明白啦! 实际上手体验maven面对冲突Jar包的加载规则

点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
Maven项目使用打包时使用本地jar包库
在使用maven管理项目时,有时候我们可能会使用一些第三方的jar包依赖库,但是这些jar包依赖库又没有在共有的maven仓库。通常只能下来放到本项目的lib目录下。但是我们打包时如果不做处理,那么打包后的fatjar中不会有lib文件夹中的相关jar包。打包后无法运行起来,因此需要做特殊处理,让maven打包时能够把使用到外部jar打进去。主要就是在
Stella981 Stella981
3年前
Maven 项目下slf4j 包冲突问题
今天遇到Maven下Jar包冲突问题.由于Mavenjar包是自动依赖..但是jar包依赖的版本不一样..会造成冲突就比如遇到:org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;说的slf4j
Stella981 Stella981
3年前
SpringBoot 引入本地或第三方Jar包
在开发过程中,我们会遇到一些Maven仓库没有的Jar包的情况,比如公司其他团队开发的Jar包等。这时我们就不能通过Pom文件引入。这里我们使用hutoolJar为例。一、使用Maven命令把Jar包添加到本地仓库(1)执行maven命令,把Jar添加到本地。mvninstall:installfileDfile/Us
Stella981 Stella981
3年前
Maven简介安装
什么是MavenMaven是一个由Apache公司推出的一个管理项目的工具,它包含了一个项目对象模型,一组标准集合,一个项目生命周期,一个依赖管理系统,和用来运行定义在生命周期阶段中插件目标的逻辑Maven能解决什么问题1.管理jar包,防止jar包冲突2.Maven也
Stella981 Stella981
3年前
Hbase启动hbase shell运行命令报Class path contains multiple SLF4J bindings.错误
1:Hbase启动hbaseshell运行命令报ClasspathcontainsmultipleSLF4Jbindings.错误,是因为jar包冲突了,所以对于和hadoop的jar包冲突的,可以将其他jar包删除,如果你不确定是否删除正确,可以将其他的jar包复制备份或者修改名称,确保操作以后失败了,还可以找回。SLF4J:Cl
Stella981 Stella981
3年前
Android系统源码集成高德定位SDK
由于项目需要使用定位功能并且系统可自由定制,所以考虑如何在源码中进行集成。在源码集成之前,系统中有至少两个应用使用高德定位SDK,或许需要使用定位的模块更多,如果每个模块单独集成会造成jar包的重复利用,并且编译文件不小心会导致编译冲突,因此考虑修改实现方式,在系统源码中将定位sdk的jar包集成到framework.jar中。既然集成到系统中,那它的使用方
Maven进阶学习指南 | 京东云技术团队
当我们在开发项目时,有时需要用到外部依赖组件,例如当我们需要Json序列化的时候需要用到FastJson组件,我们可以通过下载对应jar包加载到项目中。但当一个大的项目同时需要依赖各种各样的外部服务,就存在着配置繁琐、依赖冲突等问题,因此可以通过maven来完成对应的依赖管理功能。
实际上手体验maven面对冲突Jar包的加载规则 | 京东云技术团队
这篇文章主要记录了本次遇到的问题:即maven在面对不同版本的jar包在pom文件中同时声明会存在加载覆盖的问题,于是通过查询网上相关资料对maven包的加载规则介绍,并通过实际场景对其进行分析验证;
京东云开发者 京东云开发者
8个月前
jar包冲突组建设计书
.背景实际开发过程中,使用maven管理jar给我们开发带来了很多便利,不需要自己一个一个的jar包下载了,只需要配置个pom配置文件就可以了,写上对应坐标和仓库地址就可以了。但是jar冲突没问题没有解决,有冲突的jar包maven不会给我们检查出来还是会
死牛胖子 死牛胖子
5个月前
Maven如何解决版本依赖冲突
Maven的依赖具备传递性,一个项目会依赖很多包,这些依赖包又会依赖其它包,从而构成复杂的依赖关系,这其中相同的包可能会被多次依赖,如果依赖了多个版本,就会产生冲突,此时,Maven需要一个选择策略,从多个版本中选择一个版本。Maven会根据以下两个原则来