【问题标题】:maven dependency plugin ignores dependency versions? [duplicate]maven依赖插件忽略依赖版本? [复制]
【发布时间】:2017-02-09 15:41:30
【问题描述】:

在我看来,maven 依赖插件在计算依赖列表时行为不端。

假设这 3 个项目:

base1:

<?xml version="1.0" encoding="UTF-8"?>                                                                                                                            
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>mygroup</groupId>
    <artifactId>base1</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
      <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.3</version>
      </dependency>
    </dependencies>
</project>

base2:

<?xml version="1.0" encoding="UTF-8"?>                                                                                                                            
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>mygroup</groupId>
    <artifactId>base2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
      <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
      </dependency>
    </dependencies>
</project>

综合:

<?xml version="1.0" encoding="UTF-8"?>                                                                                                                            
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>mygroup</groupId>
    <artifactId>combined</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
      <dependency>
        <groupId>mygroup</groupId>
        <artifactId>base1</artifactId>
        <version>1.0-SNAPSHOT</version>
      </dependency>
      <dependency>
        <groupId>mygroup</groupId>
        <artifactId>base2</artifactId>
        <version>1.0-SNAPSHOT</version>
      </dependency>
    </dependencies>
</project>

base1 和 base2 都依赖于 commons-lang,但每个版本都不同! 组合取决于 base1 和 base2。

在组合调用mvn dependency:list 时,我希望在 2.3 和 2.6 版本中看到 base1、base2 和 commons-lang,因为它们都被使用了。 然而实际输出是:

[INFO] The following files have been resolved:
[INFO]    commons-lang:commons-lang:jar:2.3:compile
[INFO]    mygroup:base1:jar:1.0-SNAPSHOT:compile
[INFO]    mygroup:base2:jar:1.0-SNAPSHOT:compile

它甚至不使用版本号最高的通用语言,而只是使用它首先找到的那个。

我怎样才能避免这种情况?我需要所有依赖项。

【问题讨论】:

  • 最适合您的是更改需要依赖 commons-lang:2.3 的代码。对不起...
  • @otonglet 如果 base1 和 base2 是第三方模块,我做不到。
  • @radlan 你是不是把mvn dependency:listmvn dependency:tree 混淆了?
  • @nullpointer 不,我更多地谈论用于计算依赖关系的实际算法。 mvn dependency:copy-dependencies 是实际使用的。但是因为和mvn dependency:list一样,我提到了这个,因为它更容易举个例子。

标签: java maven dependencies maven-dependency-plugin


【解决方案1】:

据此official documentation(相关部分以粗体突出显示):

依赖中介 - 这决定了当遇到工件的多个版本时将使用哪个版本的依赖。目前,Maven 2.0 仅支持使用“最近定义”,这意味着它将使用依赖树中与您的项目最接近的依赖版本。您始终可以通过在项目的 POM 中明确声明来保证版本。 请注意,如果两个依赖版本在依赖树中的深度相同,则在 Maven 2.0.8 之前没有定义哪个会获胜,但从 Maven 2.0.9 开始,重要的是声明中的顺序:第一个声明获胜。

因此,Maven 选择 2.3 版本,因为它在依赖解析过程中首先遇到。请注意,如果您在 combined 模块上运行 mvn dependency:tree,它将显示使用了哪个版本以及省略了哪个版本。

最好的解决方案是在 combined 工件中明确选择您想要的版本,方法是在其 POM 中声明依赖项,以便 Maven 优先于其他版本:

<?xml version="1.0" encoding="UTF-8"?>
<project>
   <modelVersion>4.0.0</modelVersion>
   <groupId>mygroup</groupId>
   <artifactId>combined</artifactId>
   <version>1.0-SNAPSHOT</version>
   <packaging>jar</packaging>

   <dependencies>
     <dependency>
       <groupId>mygroup</groupId>
       <artifactId>base1</artifactId>
       <version>1.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>mygroup</groupId>
       <artifactId>base2</artifactId>
       <version>1.0-SNAPSHOT</version>
     </dependency>
     <dependency>    <!-- This will override the versions in base1 and base2 -->
       <groupId>commons-lang</groupId>
       <artifactId>commons-lang</artifactId>
       <version>2.6</version>
     </dependency>
   </dependencies>

请注意,Maven 不能选择两个版本,因为在这种情况下,您项目的类路径中的相同类会有两个定义,这可能会导致运行时出现意外问题。

【讨论】:

  • 实际上这似乎是唯一的解决方案。这不是我想要的,因为例如 base1 和 base2 是可执行应用程序,它们的类路径是在构建时生成的,组合起来只是一个 container 对于那些组装所有依赖项的应用程序,base2 将无法运行,因为其类路径的依赖不包含在组装的依赖中。但是,我似乎被困在这里,您的建议可能是最好的解决方案。
  • @radlan 我可能遗漏了一些东西,但根据您所说的“base1 和 base2 是可执行应用程序”的描述,您似乎应该将构建分成两个单独的构建,其中构建 #1 构建 base1并且 build #2 构建 base2,在这种情况下,每个构建都使用自己独立的依赖版本。无论如何,这里有一个似乎相关的帖子:stackoverflow.com/questions/24962607/…。我碰巧也回答了。在这种情况下,您也许可以使用 Maven 配置文件。每个配置文件都可以声明自己的依赖项。
  • base1 和 base2 有不同的构建。但是还有另一个构建,组合在一起,捆绑了其他构建以简化整个捆绑的部署。
【解决方案2】:

Maven 从上到下扫描 pom 并使用它遇到的第一个版本。

假设您确实需要两个版本的 commons-lang,您可以将这两个版本放在您的项目中并使用 maven 将它们打包到您的 jar 中。

然而,编译器如何知道对 StringUtils.isEmpty() 的调用是否调用了 2.3 或 2.6 版本?

Same discussion here.

【讨论】:

    【解决方案3】:

    Maven 总是使用“最近获胜”策略来解决冲突。您可以运行以下命令来查看使用特定版本的原因:

    mvn dependency:tree -Dverbose -Dincludes=commons-lang
    

    有关详细信息,请参阅以下内容: https://maven.apache.org/plugins/maven-dependency-plugin/examples/resolving-conflicts-using-the-dependency-tree.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-03
      • 2015-05-12
      • 1970-01-01
      • 2016-09-18
      • 2015-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多