• Maven提高篇系列之(五)——处理依赖冲突


    这是一个Maven提高篇的系列,包含有以下文章:

    1. Maven提高篇系列之(一)——多模块 vs 继承
    2. Maven提高篇系列之(二)——配置Plugin到某个Phase(以Selenium集成测试为例)
    3. Maven提高篇系列之(三)——使用自己的Repository(Nexus)
    4. Maven提高篇系列之(四)——使用Profile
    5. Maven提高篇系列之(五)——处理依赖冲突
    6. Maven提高篇系列之(六)——编写自己的Plugin(本系列完)

      

    在本系列的上一篇文章中,我们讲到了如何使用Profile,在本文中,我们将讲到如何处理Maven的依赖冲突。

     

    不知道你在使用Maven时是否遇到过诸如"NoSuchMethodError"或"ClassNotFoundException"之类的问题,甚至发生这些问题的Java类你没都没有听说过。要搞清楚这里面的缘由,我们得学习Maven对依赖冲突的处理机制。

     

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

     

    请下载本文的github源代码:https://github.com/davenkin/maven-dependency-conflict-demo

     

    我们有一个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版本作为最终的依赖。这和Gradle不同,Gradle在默认情况下将选择最新的版本作为获胜版本。而对于Maven,由于proejct-common的1.0版本比2.0版本在依赖树中离resolve-web更近,故1.0版本获胜。在resolve-web中执行"mvn dependency:tree -Dverbose"可以看到resolve-web的依赖关系:

     

    [INFO] resolve-web:resolve-web:war:1.0-SNAPSHOT
    
    [INFO] +- junit:junit:jar:3.8.1:test
    
    [INFO] +- project-B:project-B:jar:1.0:compile
    
    [INFO] |  - project-C:project-C:jar:1.0:compile
    
    [INFO] |     - (project-common:project-commmon:jar:2.0:compile - omitted for conflict with 1.0)
    
    [INFO] +- project-A:project-A:jar:1.0:compile
    
    [INFO] |  - project-common:project-commmon:jar:1.0:compile
    
    [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”。(请根据本文github工程中的README.md中的步骤重现该错误信息。)

     

    对于这种有依赖冲突所导致的问题,我们有两种解决方法。

     

    方法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>  

    此时再在resolve-web中执行"mvn dependency:tree -Dverbose",结果如下:

     

    ......
    
    [INFO] resolve-web:resolve-web:war:1.0-SNAPSHOT
    
    [INFO] +- junit:junit:jar:3.8.1:test
    
    [INFO] +- project-B:project-B:jar:1.0:compile
    
    [INFO] |  - project-C:project-C:jar:1.0:compile
    
    [INFO] |     - project-common:project-commmon:jar:2.0:compile
    
    [INFO] +- project-A:project-A:jar:1.0:compile
    
    [INFO] - javax.servlet:servlet-api:jar:2.4:provided
    
    ......

    此时的依赖树中已经不包含project-common的1.0版本了。

     

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

     

    下一篇文章中,我们将讲到如何编写自己的Plugin。

  • 相关阅读:
    vue中插槽的理解
    父子组件的通信
    vue3.0怎么禁用eslint校验代码和修改端口号
    三大排序
    让机器人实现自主行走 没你想的那么难
    国内外知名激光雷达公司盘点
    激光雷达寿命短,思岚通过什么技术来解决?
    浅谈SLAM的回环检测技术
    除了ROS, 机器人定位导航还有其他方案吗?
    思岚科技即将登陆“2018日本机器人周”精彩抢先看
  • 原文地址:https://www.cnblogs.com/davenkin/p/advanced-maven-resolve-dependencies-conflicts.html
Copyright © 2020-2023  润新知