您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

解决maven依赖冲突,这篇就够了

时间:2022-06-16 10:45:36  来源:  作者:Java码农之路

一、前言

什么是依赖冲突

依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成了包版本冲突。

依赖冲突的原因

我们在maven项目的pom中 一般会引用许许多多的dependency。例如,项目A有这样的依赖关系:

A -> C -> X(1.0)
B -> D -> X(2.0)

X是A的传递性依赖,但是两条依赖路径上有两个版本的X,那么哪个X会被Maven解析使用呢? 两个版本都被解析显然是不对的,因为那会造成依赖重复,因此必须选择一个。

至于怎么选肯定有它的规则(下面会讲),这里我们先假设最终引用的X(1.0)版本,这样会不会有问题呢?

当然会有的

1、你想如果B引用X(2.0)的新创建的类,但因为最终被解析的是X(1.0),所以就会出现很典型的NoClassDefFoundError 或ClassNotFoundException依赖冲突报错。

2、如果B引用X(2.0)的新创建的方法,但因为最终被解析的是X(1.0),所以就会抛出 NoSuchMethodError系统异常。

但换种角度,如果最终解析的是X(2.0),就没问题了吗?

那也不一定

1、如果X(2.0)删掉了X(1.0)的一些类,但A已经引用了,同样也会报NoClassDefFoundError或者ClassNotFoundException错误。

2、如果X(2.0)删掉了X(1.0)的一些方法,但A已经引用了,同样也会报NoSuchMethodError错误。

所以说具体问题还需具体分析,到底采用哪个版本还需要看实际项目。也可能我们需要升级对应的A或者B的版本才能解决问题。

如果有两个版本的X,Maven是依据什么原则来选择解析哪个X呢?


 

二、maven依赖原则

maven依赖主要有两大原则

1、路径最近者优先

相同jar不同版本,根据依赖的路径长短来决定引入哪个依赖。

举例

依赖链路一:A -> B -> C -> X(1.0)
依赖链路二:F -> D -> X(2.0)

该例中X(1.0)的路径长度为3,而X(2.0)的路径长度为2,因此X(2.0)会被解析使用。依赖调解第一原则不能解决所有问题,比如这样的依赖关系:

A -> B -> Y(1.0)
c -> D -> Y(2.0)

Y(1.0)和Y(2.0)的依赖路径长度是一样的,都为2。Maven定义了依赖调解的第二原则:

2、第一声明者优先

在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用,顺序最前的那个依赖优胜。该例中,如果A的依赖声明在C之前,那么Y (1.0)就会被解析使用.

注意 子pom内声明的优先于父pom中的依赖。


 

三、如何排除依赖

我们先来解释下什么是传递性依赖

1、什么是传递性依赖

比如当我们项目中,引用了A的依赖,A的依赖通常又会引入B的jar包,B可能还会引入C的jar包。

这样,当你在pom.xml文件中添加了A的依赖,Maven会自动的帮你把所有相关的依赖都添加进来。

这里随便举一个例子,比如我们为了实现导入导出功能我们可能会引入poi

  <dependency>
     <groupId>org.Apache.poi</groupId>
     <artifactId>poi-ooxml</artifactId>
     <version>3.10.1</version>
  </dependency>

当你引入它的时候,它其实还会映入其它jar包

  <dependencies>
    <dependency>
       <groupId>org.apache.poi</groupId>
       <artifactId>poi</artifactId>
       <version>3.10.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml-schemas</artifactId>
      <version>3.10.1</version>
    </dependency>
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.6.1</version>
    </dependency>
 </dependencies>

就这样一层层的,Maven会自动的帮你把所有相关的依赖都添加进来。传递性依赖会给项目引入很多依赖,简化项目依赖管理,但是也会带来问题。

最明显的就是容易发生依赖冲突。

2、如何排除依赖

关键字:exclusions

exclusions可以包含一个或者多exclusion子元素,因此可以排除一个或者多个传递性依赖。

需要注意的是,声明exclusion的时候只需要groupld和artifactld,而不需要要version元素。

示例

   <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.10.1</version>
            <!--排除poi依赖-->
        <exclusions>
            <exclusion>
                <artifactId>poi</artifactId>
                <groupId>org.apache.poi</groupId>
             </exclusion>
        </exclusions>
   </dependency>


 

四、实例演示如何解决依赖冲突

我们先来复现因为依赖冲突导致项目报错的。

1、制造依赖冲突

在当前项目中,我即引用了org.apache.poi,又引用了com.alibaba的easyExcel

pom文件如下:

   <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.10.1</version>
   </dependency>
   <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>2.2.8</version>
   </dependency>

然后在项目中添加如下代码:

@SpringBootApplication
public class MAInApplication {

	public static void main(String[] args) {
		SpringApplication.run(MainApplication.class, args);
		test();

	}
	public static void test() {
		//1.获取文件地址
		String fileName = "/excel/test.xlsx";
		//2、调用easyExcel里面的方法实现写操作
		EasyExcel.write(fileName, UserDto.class).sheet("某某报表").doWrite(new ArrayList<>());
	}
}	

我们发现在SpringBoot启动的时候就报NoClassDefFoundError异常了。

解决maven依赖冲突,这篇就够了

 

这就是依赖冲突导致的异常报错。

为什么会这样呢,我们可以通过idea看下,打开maven菜单,点击show dependencies。

解决maven依赖冲突,这篇就够了

 

看到这里你大概就已经明白,因为我当前的easyexcel引入的poi是3.17版本的,但是因为根据maven依赖原则,实际引入的poi版本确实是3.10.1版本的。


DefaultTempFileCreationStrategy这个类在3.10.1这个版本并没有,只有3.17版本才有,所以报了这个错误,这么一解释是不是都通了。

然后我们再来思考一个问题,上面这个案例我们一眼就知道是最终应用哪个依赖里的哪个版本,但如果你的项目中依赖许许多多的jar,肉眼排查就没那么方便了,这里推荐一个

Maven管理插件

2、Maven Helper插件分析jar包冲突

选择并下载插件

解决maven依赖冲突,这篇就够了

 

在pom文件中看到 dependency analyzer标志,说明maven helper插件就安装成功了。

解决maven依赖冲突,这篇就够了

 

点击dependency analyzer之后就会进入到下面的页面

解决maven依赖冲突,这篇就够了

 

从图中可以看出有哪些jar存在冲突,存在冲突的情况下最终采用了哪个依赖的版本。标红的就是冲突版本,白色的是当前的解析版本

如果我们想保留标红的版本,那我们可以标白区域右击选择排除(Exclude)

解决maven依赖冲突,这篇就够了

 

然后我们再来看pom文件,发现在org.apache.poi中已经移除了poi了。

   <dependency>
       <groupId>org.apache.poi</groupId>
       <artifactId>poi-ooxml</artifactId>
       <version>3.10.1</version>
       <exclusions>
          <exclusion>
             <artifactId>poi</artifactId>
             <groupId>org.apache.poi</groupId>
           </exclusion>
       </exclusions>
    </dependency>
    <dependency>
       <groupId>com.alibaba</groupId>
       <artifactId>easyexcel</artifactId>
       <version>2.2.6</version>
    </dependency>

我们再来看最终引用的poi版本是哪个?

解决maven依赖冲突,这篇就够了

 

我们发现最终的版本最终已经变成3.17版本,现在再启动就不会报错了,成功解决依赖冲突问题。


 

五、总结

一般我们在解决依赖冲突的时候,都会选择保留jar高的版本,因为大部分jar在升级的时候都会做到向下兼容,所以只要保留高的版本就不会有什么问题。

但是有些包,版本变化大没法去做向下兼容,高版本删了低版本的某些类或者某些方法,那么这个时候就不能一股脑的去选择高版本,但也不能选择低版本。

就比如下面这个案例

依赖链路一:A -> B -> C -> X(1.0)
依赖链路二:F -> D -> X(2.0)

X(2.0) 没有对 X(1.0) 做向下兼容也就是说可能存在排除哪个都不行,那怎么办我们只能考虑升级A的版本或者降低F的版本。比如A升级到A(2.0),使它依赖的X版本

变成X(2.0)这样的话就解决依赖冲突。

但话有说回来 A升级到A(2.0) 可能会影响许许多多的地方,比如自己项目中代码是否需要改变,或者因为 A升级到A(2.0) 导致 B和C的版本有所改变,这些影响点都需要我

们去考虑的。所以说为什么说一个大型项目稳定后,pom文件的升级是件繁琐的事情,那是因为考虑的东西是在太多了,稍有不慎就会因为依赖冲突而导致系统报错。



Tags:maven   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
使用Maven和Tomcat创建并部署Java应用
引言本文分享使用Maven和Tomcat创建、构建和部署简单的Java Web应用程序的过程。Maven是个强大的构建自动化工具,可以帮助管理项目依赖关系并自动化构建任务,而Tomcat是被广泛...【详细内容】
2023-12-11  Search: maven  点击:(172)  评论:(0)  加入收藏
教你如何选择Gradle和Maven
在软件开发领域,构建工具对于自动化编译、测试和打包代码过程至关重要。Gradle 和 Maven 是当今最流行的两种构建工具,每种工具都有自己的一套功能和优点。Gradle 是一种现代...【详细内容】
2023-10-08  Search: maven  点击:(299)  评论:(0)  加入收藏
聊聊 Maven 最佳实践
本文翻译自国外论坛 medium,原文地址:https://medium.com/@AlexanderObregon/maven-best-practices-tips-and-tricks-for-java-developers-438eca03f72bMaven 简介Maven 是一...【详细内容】
2023-09-09  Search: maven  点击:(327)  评论:(0)  加入收藏
10个Java项目中必备的Maven插件
介绍Maven是Java开发人员必备的构建工具和项目管理工具。它采用简单的项目对象模型(POM),实现Java应用程序的自动化构建、测试和部署。使用Maven插件,开发人员能够进一步扩展工...【详细内容】
2023-08-17  Search: maven  点击:(322)  评论:(0)  加入收藏
Maven进阶学习指南
前言当我们在开发项目时,有时需要用到外部依赖组件,例如当我们需要Json序列化的时候需要用到FastJson组件,我们可以通过下载对应jar包加载到项目中。但当一个大的项目同时需要...【详细内容】
2023-06-25  Search: maven  点击:(274)  评论:(0)  加入收藏
java开发人你用的maven构建还是gradle
Gradle和Maven都是Java项目构建工具,它们之间最主要的区别在于以下几点: 构建脚本语言:Maven使用XML作为构建脚本语言,而Gradle使用Groovy语言,Groovy是一种基于Java的动态语言。...【详细内容】
2023-05-16  Search: maven  点击:(458)  评论:(0)  加入收藏
记一次内网maven私服初始化方法
背景 纯内网环境,无法连互联网 待初始化maven私服在内网,无法通过配置代理完成初始化 通过nexus部署私服,初始化maven依赖和npm依赖初始化思路 通过nexus管理端上传组件功能上...【详细内容】
2023-02-27  Search: maven  点击:(276)  评论:(0)  加入收藏
Maven从入门到精通 pringBoot搭建SSM项目的完整过程 !
01、新建一个springboot项目 选择依赖和版本 SpringBoot整合lomboklombok是一个快速生成javabean的一个工具工程和生成日志的工具。未来给我们提供了很大的遍历。需要在ide...【详细内容】
2023-02-09  Search: maven  点击:(183)  评论:(0)  加入收藏
安全同学讲Maven间接依赖场景的仲裁机制
一 背景为什么想写此文去年的Log4j-core的安全问题,再次把供应链安全推向了高潮。在供应链安全的场景,蚂蚁集团在静态代码扫描平台-STC和资产威胁透视平台-哈勃这2款产品的联...【详细内容】
2022-09-22  Search: maven  点击:(344)  评论:(0)  加入收藏
Maven依赖的作用域你到底用对了没有
Maven是目前Java开发主要使用的依赖管理构建工具之一,但是很多人在引用依赖的时候直接引用坐标,而没有考虑依赖的作用范围,结果导致出现这样和那样的问题。今天胖哥就来说明一...【详细内容】
2022-07-26  Search: maven  点击:(407)  评论:(0)  加入收藏
▌简易百科推荐
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  vivo互联网技术    Tags:Java 8   点击:(18)  评论:(0)  加入收藏
如何编写高性能的Java代码
作者 | 波哥审校 | 重楼在当今软件开发领域,编写高性能的Java代码是至关重要的。Java作为一种流行的编程语言,拥有强大的生态系统和丰富的工具链,但是要写出性能优异的Java代码...【详细内容】
2024-03-20    51CTO  Tags:Java代码   点击:(25)  评论:(0)  加入收藏
在Java应用程序中释放峰值性能:配置文件引导优化(PGO)概述
译者 | 李睿审校 | 重楼在Java开发领域,优化应用程序的性能是开发人员的持续追求。配置文件引导优化(Profile-Guided Optimization,PGO)是一种功能强大的技术,能够显著地提高Ja...【详细内容】
2024-03-18    51CTO  Tags:Java   点击:(31)  评论:(0)  加入收藏
Java生产环境下性能监控与调优详解
堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。堆被划分为新生代和老年代,新生代又被进一步划分为 Eden 和 Survivor 区,...【详细内容】
2024-02-04  大雷家吃饭    Tags:Java   点击:(61)  评论:(0)  加入收藏
在项目中如何避免和解决Java内存泄漏问题
在Java中,内存泄漏通常指的是程序中存在一些不再使用的对象或数据结构仍然保持对内存的引用,从而导致这些对象无法被垃圾回收器回收,最终导致内存占用不断增加,进而影响程序的性...【详细内容】
2024-02-01  编程技术汇  今日头条  Tags:Java   点击:(77)  评论:(0)  加入收藏
Java中的缓存技术及其使用场景
Java中的缓存技术是一种优化手段,用于提高应用程序的性能和响应速度。缓存技术通过将计算结果或者经常访问的数据存储在快速访问的存储介质中,以便下次需要时可以更快地获取。...【详细内容】
2024-01-30  编程技术汇    Tags:Java   点击:(78)  评论:(0)  加入收藏
JDK17 与 JDK11 特性差异浅谈
从 JDK11 到 JDK17 ,Java 的发展经历了一系列重要的里程碑。其中最重要的是 JDK17 的发布,这是一个长期支持(LTS)版本,它将获得长期的更新和支持,有助于保持程序的稳定性和可靠性...【详细内容】
2024-01-26  政采云技术  51CTO  Tags:JDK17   点击:(98)  评论:(0)  加入收藏
Java并发编程高阶技术
随着计算机硬件的发展,多核处理器的普及和内存容量的增加,利用多线程实现异步并发成为提升程序性能的重要途径。在Java中,多线程的使用能够更好地发挥硬件资源,提高程序的响应...【详细内容】
2024-01-19  大雷家吃饭    Tags:Java   点击:(111)  评论:(0)  加入收藏
这篇文章彻底让你了解Java与RPA
前段时间更新系统的时候,发现多了一个名为Power Automate的应用,打开了解后发现是一个自动化应用,根据其描述,可以自动执行所有日常任务,说的还是比较夸张,简单用了下,对于office、...【详细内容】
2024-01-17  Java技术指北  微信公众号  Tags:Java   点击:(105)  评论:(0)  加入收藏
Java 在 2023 年仍然流行的 25 个原因
译者 | 刘汪洋审校 | 重楼学习 Java 的过程中,我意识到在 90 年代末 OOP 正值鼎盛时期,Java 作为能够真正实现这些概念的语言显得尤为突出(尽管我此前学过 C++,但相比 Java 影响...【详细内容】
2024-01-10  刘汪洋  51CTO  Tags:Java   点击:(82)  评论:(0)  加入收藏
站内最新
站内热门
站内头条