【问题标题】:Maven dependency resolution (conflicted)Maven 依赖解析(冲突)
【发布时间】:2011-11-02 18:35:38
【问题描述】:

假设我有四个项目:

  • 项目 A(依赖于 B 和 D)
  • 项目 B(依赖于 D)
  • 项目 C(依赖于 D)
  • 项目 D

在这种情况下,如果我运行项目 A,Maven 将正确解析对 D 的依赖关系。如果我理解正确,Maven 总是采用最短路径的依赖关系。由于 D 是 A 的直接依赖项,因此将使用它而不是 B 中指定的 D。

但现在假设这个结构:

  • 项目 A(依赖于 B 和 C)
  • 项目 B(依赖于 D)
  • 项目 C(依赖于 D)
  • 项目 D

在这种情况下,解决 D 的路径具有相同的深度。发生的事情是 Maven 会发生冲突。我知道可以告诉 Maven 他应该排除依赖项。但我的问题是如何解决这类问题。我的意思是在现实世界的应用程序中,你有很多依赖关系,也可能有很多冲突。

最佳实践解决方案真的是排除东西还是有其他可能的解决方案?当我突然得到一个 ClassNotFound 异常时,我发现很难处理,因为某些版本已更改,这导致 Maven 采用不同的依赖项。当然,知道了这个事实就更容易猜出问题是依赖冲突了。

我正在使用 maven 2.1-SNAPSHOT。

【问题讨论】:

  • 我认为你不应该使用 DEV 版本的 2.1-SNAPSHOT 版本。 Maven 2 在最终版本 2.2.1 中可用。
  • 顺便说一句,Maven 3.x 已经稳定了一段时间,比 maven 2.x 更快更可靠
  • 钻石是程序员最大的敌人...
  • @Sean Patrick Floyd 所有 maven 版本都比 SNAPSHOT 更稳定 :)

标签: java maven-2 maven


【解决方案1】:

解决此类情况的 maven 方法是在项目的根 pom 中包含 <dependencyManagement> 部分,您可以在其中指定将使用哪个版本的库。

编辑:

<dependencyManagement>
  <dependencies>
    <dependency>
        <groupId>foo</groupId>
        <artifactId>bar</artifactId>
        <version>1.2.3</version>
    </dependency>
   </dependencies>
</dependencyManagement>

现在无论依赖项请求哪个版本的库 foo:bar,版本 1.2.3 将始终用于此项目和所有子项目。

参考:

【讨论】:

  • 如果项目 D、项目 B 的版本不同怎么办(依赖于 D1.0) - 不能与 D2.0 一起使用 项目 C(依赖于 D2.0) - 不能使用 D1.0
  • @Nitul 那么你基本上就完蛋了。然后,您唯一的选择是使用 maven shade 插件之类的东西重新打包其中一个依赖项
  • 澄清一下,dependencyManagement 中指定的版本号适用于传递依赖,以及没有明确版本的项目依赖。但是具有显式版本的项目依赖项会覆盖 dependencyManagement 部分中的版本。
【解决方案2】:

Maven 可以处理这两种情况而不会产生任何冲突。当需要传递依赖的两个版本时,将存在冲突。 ClassNotFoundException 您描述了应用程序(或依赖项)尝试使用在实际使用的冲突依赖项版本中不可用的类的结果。 有多种方法可以解决此问题。

  1. 更新您正在使用的依赖于冲突依赖项的库的版本,以便它们都依赖于该依赖项的相同版本
  2. 将冲突的依赖项声明为您的项目与您想要包含的版本的直接依赖项(在示例中,其中包含缺少类的版本)
  3. 通过 POM 的 &lt;dependencyManagement&gt; 部分指定传递依赖项应使用的冲突依赖项的哪个版本
  4. 使用&lt;exclusion&gt; 明确排除冲突依赖项的不需要版本,使其不包含在依赖它们的依赖项中

【讨论】:

    【解决方案3】:

    这根本不是 maven 问题,而是 java 问题。 如果项目 B 和项目 C 需要项目 D 的两个不兼容版本,则不能在项目 A 中同时使用它们。

    不幸的是,如您所知,Maven 解决此类冲突的方法是选择排除哪些冲突。

    使用mvn dependency:analyzemvn dependency:tree 有助于找出您有哪些冲突。

    【讨论】:

    • +1。我会说不向后兼容的工件应该更改它们的 groupId 和/或 artifactId。
    • 是的,但这只需要你完成一半。工件不得包含具有相同包和名称的类。
    • 是的,很遗憾。在这种情况下,您将需要 ProGuard 或 Maven Shade 插件
    • OSGI 会解决这个假设的场景吗? (并不是说这是一个简单的解决方案——只是问问而已。)
    • 可能。我不知道 OSGI 好到可以肯定地说什么。
    【解决方案4】:

    您可以使用规则Dependency Convergence 在整个项目中enforce 一致的依赖项。

     <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-enforcer-plugin</artifactId>
         <version>1.3.1</version>
         <executions>
            <execution>
               <id>enforce</id>
               <configuration>
                  <rules>
                     <DependencyConvergence/>
                  </rules>
               </configuration>
               <goals>
                  <goal>enforce</goal>
               </goals>
            </execution>
         </executions>
      </plugin>
    

    【讨论】:

      【解决方案5】:

      一种可能的策略是为主项目指定要使用的 D 版本(最新版本 f.g.)。但是,如果库 D 不向后兼容,则您会遇到 kukudas 所述的问题 - 在您的项目中使用这两个库是不可能的。

      在这种情况下,可能需要在旧版本中使用 B 或 C,以便两者都依赖于 D 的兼容版本。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-12
        • 2013-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-20
        • 1970-01-01
        相关资源
        最近更新 更多