一、依赖原则

假设,在 JavaMavenService2 模块中,log4j 的版本是 1.2.7,在 JavaMavenService1 模块中,它虽然继承于 JavaMavenService2 模块,但是它排除了在 JavaMavenService2 模块中继承 1.2.7 的版本,自己引入了1.2.9log4j版本。

此时,相对于 WebMavenDemo 而言,log4j.1.2.7.jar 的依赖路径是 JavaMavenService1 >> JavaMavenService2 >> log4j.1.2.7.jar,长度是 3;而 log4j.1.2.9.jar 的依赖路径是 JavaMavenService1 >> log4j.1.2.7.jar 长度是 2。

所以 WebMavenDemo 继承的是 JavaMavenService1 模块中的 log 版本,而不是 JavaMavenService2 中的,这叫路径优先原则(谁路径短用谁)

此外,在路径相同的情况下,

这种场景依赖关系发生了变化,WebMavenDemo 项目依赖 Sercive1Service2,它俩是同一个路径,那么谁在 WebMavenDemopom.xml 中先声明的依赖就用谁的版本。这叫先定义先使用原则

比如:先声明 JavaMavenService1 所以 WebMavenDemo 继承它的 log4j.1.2.9.jar 依赖

<!--先声明 JavaMavenService1 所以 WebMavenDemo 继承它的 log4j.1.2.9.jar 依赖-->
<dependency>
<groupId>com.nasus</groupId>
<artifactId>JavaMavenService1</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.nasus</groupId>
<artifactId>JavaMavenService2</artifactId>
<version>1.0.0</version>
</dependency>
  • 参考:cnblogs.com/hzg110/p/6936101.html

二、依赖冲突的原因

项目的依赖 service1 和依赖 service2 同时引入了依赖 log4j。这时,如果依赖 log4jservice1service2 中的版本不一致就可能导致依赖冲突。如下图:

注意,上面我用的是可能,并不是说满足上面的条件就一定会发生依赖冲突。因为 maven 遵循上面提到的两个原则:

  • 先定义先使用原则 (路径层级相同情况下)
  • 路径优先原则(谁路径短用谁)

2.1 依赖冲突会报什么错?

依赖冲突通常两个错:NoClassDefFoundErrorNoSuchMethodError,逐一讲解下导致这两种错误的原因:

  • 以上图依赖关系为例,假设 WebDemo 通过排除 service1 中低版本的依赖,从而继承 service2 中的高版本的依赖。这时,如果 WebDemo 在执行过程中调用 log4j(1.2.7) 有,但是升级到 log4j(1.2.9)就缺失的类 log,就会导致运行期失败,出现很典型的依赖冲突时的 NoClassDefFoundError 错误。

  • 还是以上图依赖关系为例,WebDemo 通过排除 service1 中低版本的依赖,从而继承 service2 中的高版本的依赖。WebDemo 调用了原来 log4j(1.2.7) 中有的方法 log.info(),但升级到 log4j(1.2.7) 后,log.info() 不存在了,就会抛出 NoSuchMethodError 错误.

所以说,当存在依赖冲突时,仅指望 maven 的两个原则来解决是不成熟的。不管是路径优先原则还是先定义先使用原则,都有可能造成以上的依赖冲突。那么如何解决它呢?

三、解决依赖冲突

通过上面的分析我们应该能理解到,解决依赖冲突的核心就是使冲突的依赖版本统一,而且项目不报错

我们可以通过运行 maven 命令:mvn dependency:tree 查看项目的依赖树分析依赖,看那些以来有冲突,还是以上图举例:运行命令之后,查看依赖树的 log4j 依赖就会得到错误提示: (1.2.7 omitted for conflict with 1.2.9)

知道了如何查看冲突之后,就是解决冲突。

1、尝试升高 service2 的版本使他依赖的 log 版本与 service1log 版本一致,但它可能会导致 service2 不能工作。

2、如果 service2 是个旧项目,找遍了也没找到与 service1 版本一致的 log,这时可以尝试拉低 service1 的版本使他依赖的 log 版本与 service2log 版本一致,但可能会导致 service1 不能工作。

你可能说了,这又不行,那又不行,怎么办呢?别急,往下看,maven 解决依赖冲突主要用两种方法:

  • 排除低版本,直接用高版本

最理想的状况就是直接排除低版本,依赖高版本,一般情况下高版本会兼容低版本。如果 service2 并没有调用 log4j.1.2.9 升级所摒弃的方法或类时, 可以使用 <exclusion> 标签,排除掉 service2 中的 log。还是以上图举例:

<dependency>
<groupId>com.nasus</groupId>
<artifactId>service2</artifactId>
<version>1.0.0</version>
<!-- 排除低版本 log4j -->
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>

看着到这里,你可能又说了。如果 service2 有用到 log 升级所摒弃的方法或类;而 service1 又必须用新版本的 log,怎么办?

第一,一般情况下,第三方依赖不会出现这种情况。如果出现了,那你就到 maven 中央仓库找下兼容两个版本的依赖。如果找不到,那只能换依赖。

第二,如果是自己公司的 jar 出现这种情况,那就是你们的 jar 管理非常混乱。建议重新开发,兼容旧版本。

四、使用 Maven Helper 插件解决依赖冲突

idea plugin 中搜索 maven helper 插件安装完之后,打开 pom 文件,发现左下角有个 Depandency Analyzer 选项,点击进入选 conflicts 选项,就可以看到当前有冲突的 jar 包,在右边 exclude 掉红色冲突的版本即可。

最后

如果看到这里,喜欢这篇文章的话,请转发、点赞。微信搜索「一个优秀的废人」,欢迎关注。

回复「1024」送你一套完整的 java、python、c++、go、前端、linux、算法、大数据、人工智能、小程序以及英语教程。

回复「电子书」送你 50+ 本 java 电子书。

Maven 基础(二) | 解决依赖冲突的正确姿势的更多相关文章

  1. 【maven】maven查看项目依赖并解决依赖冲突的问题

    一.问题 项目开发过程中,经常会遇到jar冲突,然后maven根据自己的规则进行冲突解决,导致项目在运行的过程中报错. 1.maven自动解决依赖冲突的规则是什么? 2.如何查看当前项目的maven的 ...

  2. 利用mvn/maven如何检查依赖冲突,并解决依赖冲突

    mvn/maven如何检查依赖冲突,并解决依赖冲突 如图,点击图示位置,就可以把整个项目的依赖关系展示出来 在图里选中一个artifact,则所有依赖该artifact的地方都会一起连带出来突出显示, ...

  3. Maven解决依赖冲突

    依赖冲突 若项目中多个Jar同时引用了相同的Jar时,会产生依赖冲突,但Maven采用了两种避免冲突的策略,因此在Maven中是不存在依赖冲突的. 短路优先 本项目-->A.jar-->B ...

  4. Gradle依赖的统一管理,解决依赖冲突

    看见别人在用implementation rootProject.ext.dependencies["xxxx"]不知道是什么意思,上网查了一下,原来是为了解决或者说预防gradl ...

  5. 实用maven笔记二-信息&依赖管理

    目前我经历的公司的主要项目管理工具都是maven,maven除了是一个实用的构建工具外,也是一个功能强大的项目管理工具.其管理功能分为信息管理和依赖管理.通过pom.xml文件实现. 信息管理 信息管 ...

  6. Maven中解决依赖冲突的问题

    1.短路优先:谁离得最近就使用谁的依赖jar包 C到达A为C->B->A C到达B为C->B 例如: A中的 commons-io的版本为2.4 B中的commons-io的版本为2 ...

  7. 解决依赖冲突:maven-enforcer-plugin插件

    我们会经常碰到这样的问题,在pom中引入了一个jar,里面默认依赖了其他的jar包.jar包一多的时候,我们很难确认哪些jar是我们需要的,哪些jar是冲突的.此时会出现很多莫名其妙的问题,什么类找不 ...

  8. Activiti系列:如何把Activiti工程转换为maven工程以解决依赖项找不到的问题

    在eclipse中安装了Activiti插件之后,就可以新建Activiti工程,但是在实际使用时发现,在该工程中间新建Activiti Diagram,绘制好该图形之后,右键,新建单元测试,选择ju ...

  9. virtualenv 运行python 解决依赖冲突问题 尤其是django那种蛋疼的版本问题

    Create a python virtual environment and install python dependencies. cd evalai virtualenv venv sourc ...

随机推荐

  1. 【b704 && BZOJ 1999】树网的核

    [题目链接]:http://noi.qz5z.com/viewtask.asp?id=b704 &&http://www.lydsy.com/JudgeOnline/problem.p ...

  2. 分布式全局唯一ID

    方案一.UUID UUID的方式能生成一串唯一随机32位长度数据,它是无序的一串数据,按照开放软件基金会(OSF)制定的标准计算,UUID的生成用到了以太网卡地址.纳秒级时间.芯片ID码和许多可能的数 ...

  3. printk函数 打印设备编号

    偶尔地, 当从一个驱动打印消息, 你会想打印与感兴趣的硬件相关联的设备号. 打印主次 编号不是特别难, 但是, 为一致性考虑, 内核提供了一些实用的宏定义( 在 <linux/kdev_t.h& ...

  4. tab选项卡平滑滚动vue

    <html lang="en"> <head> <meta charset="UTF-8"> <title>Ti ...

  5. mac系统上访问docker容器中的ip配置

    使用 mac系统,发现docker没有 docker0网桥,无法直接在宿主机上 访问 容器的ip, 在测试的时候有这种需求,而不是通过-p的方式,可以参考下面的连接,主要就是 修改 setting.j ...

  6. Ubuntu查看cuda和cudnn版本

    查看 CUDA 版本: cat /usr/local/cuda/version.txt 查看 CUDNN 版本: cat /usr/local/cuda/include/cudnn.h | grep ...

  7. CommandPattern(命令模式)-----Java/.Net

    命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式.请求以命令的形式包裹在对象中,并传给调用对象.调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该 ...

  8. asp.net core 3.x 通用主机原理及使用

    一.前言 只是讲asp.net core 3.x通用主机的大致原理,这些东西是通过查看源码以及自己根据经验总结得来的,在文章中不会深入源码,因为个人觉得懂原理就晓得扩展点,后期碰到有需求的时候再仔细去 ...

  9. 【一起学源码-微服务】Ribbon 源码二:通过Debug找出Ribbon初始化流程及ILoadBalancer原理分析

    前言 前情回顾 上一讲讲了Ribbon的基础知识,通过一个简单的demo看了下Ribbon的负载均衡,我们在RestTemplate上加了@LoadBalanced注解后,就能够自动的负载均衡了. 本 ...

  10. 「SP122」STEVE - Voracious Steve 解题报告

    SP122 STEVE - Voracious Steve 题意翻译 Problem Steve和他的一个朋友在玩游戏,游戏开始前,盒子里有 n个甜甜圈,两个人轮流从盒子里抓甜甜圈,每次至少抓 1个, ...