Maven提高篇系列之五 -----依赖冲突

一、坑爹的aws-java-sdk-s3.jar

最近做项目,要做一个new feature,要求支持aws 的 temporary credentials,读aws 的doc,使用aws 的sdk,整个开发过程很顺利,在本地vm上测试,也通过了,高高兴兴的往master上上传代码,结果郁闷了,jenkins上的测试通不过,一检查,原来是aws引用的jar包和现有项目里的jar包冲突,jackson-databind这个jar包。对aws的jar包降版本,不能实现new feature;对原有项目里的jar包升版本,又引起别的错误,不容易修复。上网一搜索,发现吐槽这个冲突的人太多了,amazon又开发了一个新的包aws-java-sdk-bundle.jar,从而解决了这个问题。趁这个机会,把maven的相关知识复习一下。

 

二、依赖冲突常见现象

在使用Maven时是否遇到过诸如"NoSuchMethodError"或"ClassNotFoundException"之类的问题,往往会是依赖冲突造成的。

 Maven采用“最近获胜策略(nearest wins strategy)”的方式处理依赖冲突,即如果一个项目最终依赖于相同artifact的多个版本,在依赖树中离项目最近的那个版本将被使用。

 同一个jar包,在依赖树中有地位相同的版本,那么先被引用的jar文件占优

三、依赖冲突的例子。

我们有一个web应用resolve-web,该工程依赖于project-A和project-B,project-A依赖于project-common的1.0版本并调用其中的sayHello()方法。project-B依赖于project-C,而project-C又进一步依赖于project-common的2.0版本并调用其中的sayGoodBye()方法。project-common的1.0和2.0版本是不同的,1.0中之包含sayHello()方法,而2.0中包含了sayHello()和sayGoodBye()两个方法。整个项目的依赖关系如下图:

  根据Maven的transitive依赖机制,resolve-web将同时依赖于project-common的1.0和2.0版本,这就造成了依赖冲突。而根据最近获胜策略,Maven将选择project-common的1.0版本作为最终的依赖。在resolve-web中执行"mvn dependency:tree -Dverbose"可以看到resolve-web的依赖关系:

 1 [INFO] resolve-web:resolve-web:war:1.0-SNAPSHOT
 2 
 3 [INFO] +- junit:junit:jar:3.8.1:test
 4 
 5 [INFO] +- project-B:project-B:jar:1.0:compile
 6 
 7 [INFO] |  \- project-C:project-C:jar:1.0:compile
 8 
 9 [INFO] |     \- (project-common:project-commmon:jar:2.0:compile - omitted for conflict with 1.0)
10 
11 [INFO] +- project-A:project-A:jar:1.0:compile
12 
13 [INFO] |  \- project-common:project-commmon:jar:1.0:compile
14 
15 [INFO] \- javax.servlet:servlet-api:jar:2.4:provided

由上可知,project-common:project-commmon:jar:2.0被忽略掉了。此时在resolve-web的war包中将只包含project-common的1.0版本,于是问题来了。由于project-common的1.0版本中不包含sayGoodBye()方法,而该方法正是project-C所需要的,所以运行时将出现“NoSuchMethodError”。

还需要注意的一点:当一个项目有多个包时,包之间也存在依赖冲突,可以到最后做war包的那个项目里“*****-servlet”,查看依赖递归。

四、解决方法

方法1:显式加入对project-common 2.0版本的依赖。先前的2.0版本不是离resolve-web远了点吗,那我们就直接将它作为resolve-web的依赖,这不就比1.0版本离resolve-web还近吗?在resove-web的pom.xml文件中直接加上对project-common 2.0 的依赖:

 

<dependency>       
   <groupId>project-common</groupId>      
   <artifactId>project-commmon</artifactId>  
   <version>2.0</version>   
</dependency>  

 

方法2:resolve-web对project-A的dependency声明中,将project-common排除掉。在resolve-web的pom.xml文件中修改对project-A的dependency声明:

 

复制代码
<dependency>  
          <groupId>project-A</groupId>  
          <artifactId>project-A</artifactId>  
          <version>1.0</version>  
          <exclusions>  
              <exclusion>  
                  <groupId>project-common</groupId>  
                  <artifactId>project-commmon</artifactId>  
              </exclusion>  
          </exclusions>  
</dependency>  
复制代码

 另外,我们还可以在project-A中将对project-common的依赖声明为optional,optional即表示非transitive,此时当在resolve-web中引用project-A时,Maven并不会将project-common作为transitive依赖自动加入,除非有别的项目(比如project-B)声明了对project-common的transitive依赖或者我们在resolve-web中显式声明对project-common的依赖(方法一)。

转载于:https://www.cnblogs.com/shirley18/p/9634787.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值