Maven 基础(二) | 解决依赖冲突的正确姿式

1、依赖原则

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

此时,相对于 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 中的,这叫路径优先原则(谁路径短用谁)java

依赖原则

此外,在路径相同的状况下,python

路径相同

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

好比:先声明 JavaMavenService1 因此 WebMavenDemo 继承它的 log4j.1.2.9.jar 依赖c++

<!--先声明 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

2、依赖冲突的缘由

项目的依赖 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 的两个原则来解决是不成熟的。不论是路径优先原则仍是先定义先使用原则,都有可能形成以上的依赖冲突。那么如何解决它呢?

3、解决依赖冲突

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

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

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

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

二、若是 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 管理很是混乱。建议从新开发,兼容旧版本。

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

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

解决冲突

最后

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

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

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

编程语言
相关文章
相关标签/搜索