Maven依赖冲突解决

Maven项目运行过程中,如果报以下错误, 极有可能是依赖冲突造成的。

  • Caused by:java.lang.NoSuchMethodError

  • Caused by: java.lang.ClassNotFoundException

依赖冲突原理

依赖冲突指的就是我们在引入不同的依赖时,不同的依赖又引入了相同的依赖,这些相同的依赖之间就会产生版本冲突问题。举个例子来说明一下:

A->B->C->D1(log 15.0):A 中包含对 B 的依赖,B 中包含对 C 的依赖,C 中包含对 D1 的依赖,假设是 D1 是日志 jar 包,version 为 15.0。

E->F->D2(log 16.0):E 中包含对 F 的依赖,F 包含对 D2 的依赖,假设是 D2 是同一个日志 jar 包,version 为16.0。

当 pom.xml 文件中引入 A、E 两个依赖后,根据 Maven 传递依赖的原则,D1、D2 都会被引入,而 D1、D2 是同一个依赖 D 的不同版本。当我们在调用 D2 中的 method1() 方法,而 D1 中是 15.0 版本(method1可能是版本升级后增加的方法),可能没有这个方法,这样 JVM 在加载 A 中 D1 依赖的时候,找不到 method1 方法,就会报 NoSuchMethodError 的错误,此时就产生了 jar 包冲突。

依赖冲突解决方法

Maven 解析 pom.xml 文件时,同一个 jar 包只会保留一个,那么面对多个版本的 jar 包,需要怎么解决呢?

1、Maven默认处理策略

Maven的默认处理策略,如果选择了正确的版本,我们就无需再做处理,但有时候会选择错误的那个版本,导致会报错。比如选择了低版本的依赖,而这个低版本依赖中是不存在某个类的,我们去访问这个类就会报错。

  • 最短路径优先:Maven 面对 D1 和 D2 时,会默认选择最短路径的那个 jar 包,即 D2。E->F->D2 比 A->B->C->D1 路径短 1。
  • 最先声明优先:如果路径一样的话,如: A->B->C1, E->F->C2 ,两个依赖路径长度都是 2,那么就选择最先声明。

2、手动移除依赖:

用于排除某项依赖的依赖jar包,有如下二种方式:

借助Maven Helper插件移除

我们可以借助Maven Helper插件中的Dependency Analyzer分析冲突的jar包,然后在对应标红版本的jar包上面点击execlude,就可以将该jar包排除出去。再刷新以后冲突就会消失。

手动排除

或者手动在pom.xml中使用<exclusion>标签去排除冲突的jar包(上面利用插件Maven Helper中的execlude方法其实等同于该方法):

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  <version>1.4.4.RELEASE</version>
  <exclusions>
    <exclusion>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
    </exclusion>
  </exclusions>
</dependency>

3、版本锁定原则

版本锁定原则一般用在继承项目的父项目中。正常项目都是多模块的项目,如 moduleA 和 moduleB 共同依赖 X这个依赖的话,那么可以将 X 抽取出来,同时设置其版本号,这样 X 依赖在升级的时候,不需要分别对 moduleA 和 moduleB 模块中的依赖 X 进行升级,避免太多地方(moduleC、moduleD….)引用 X 依赖的时候忘记升级造成 jar 包冲突,这也是实际项目开发中比较常见的方法。

首先定义一个父 pom.xml,将公共依赖放在该 pom.xml 中进行声明:

<properties>
  <spring.version>spring4.2.4</spring.version>
<properties>

<dependencyManagement>
  <dependencies>
     <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-beans</artifactId>
       <version>${spring.versio}</version>
    </dependency>
  </dependencies>
</dependencyManagement>

这样如 moduleA 和 moduleB 在引用 Spring-beans jar 包的时候,直接使用父 pom.xml 中定义的公共依赖就可以。moduleA 在其 pom.xml 使用 spring-bean 的 jar 包时就不用再定义版本:

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
  </dependency>
</dependencies>

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
  </dependency>
</dependencies>

以上就是日常开发中解决 Maven 冲突的几个小方案,当然实际开发中 jar 包冲突的问题可能远远比这个更复杂,需要具体问题具体处理。

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真滴book理喻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值