【问题标题】:How to debug artifact replacement in Maven如何在 Maven 中调试工件替换
【发布时间】:2014-10-11 15:59:03
【问题描述】:

我有一个父项目包含十几个子项目,其中一个子项目使用org.apache.httpcomponents:httpclient:jar:4.3.5,它依赖于org.apache.httpcomponents:httpcore:jar:4.3.2

但是,httpcore 的结果版本被解析为 4.2.1 而不是 4.3.2。

以下是在 Eclipse 中选中调试选项运行 dependency:tree 时的输出提取:

...
[DEBUG] Using mirror nexus (http://192.168.0.111:8081/nexus/content/groups/public) for apache.snapshots (http://repository.apache.org/snapshots).
[DEBUG]   testArtifact: artifact=org.apache.httpcomponents:httpclient:jar:4.3.5:compile
[DEBUG]   includeArtifact: artifact=org.apache.httpcomponents:httpclient:jar:4.3.5:compile
[DEBUG]   startProcessChildren: artifact=org.apache.httpcomponents:httpclient:jar:4.3.5:compile
[DEBUG]     manageArtifactVersion: artifact=org.apache.httpcomponents:httpcore:jar:4.3.2:compile, replacement=org.apache.httpcomponents:httpcore:jar:4.2.1
[DEBUG] Using mirror nexus (http://192.168.0.111:8081/nexus/content/groups/public) for apache.snapshots (http://repository.apache.org/snapshots).
...

它只显示replacement=org.apache.httpcomponents:httpcore:jar:4.2.1,但它没有说明更换的原因。父项目的 pom.xml 使用了相当多的依赖项,即使我可以尝试一个一个删除这些依赖项并检查结果,这也会非常耗时。有没有更有效的方法来调试工件替换?


Here 几乎是来自 Eclipse 的 dependency:tree 的完整日志,并且选中了调试选项。

【问题讨论】:

  • 你试过mvn dependency:tree吗?
  • 是的,上面的输出来自dependency:tree
  • 能否请您发布完整的mvn -X dependency:tree 日志。
  • 这确实看起来有点奇怪,但至少它说明了你的罪魁祸首:[DEBUG] org.apache.httpcomponents:httpcore:jar:4.2.1:compile (version managed from 4.3.2 by org.jboss.as:jboss-as-parent:7.2.0.Final)
  • 表示 jboss 依赖正在改变 httpcore 的版本号,因为它指定了不同的版本。见here。当然,如果您指定直接依赖项而不是传递依赖项,则您始终可以在自己的 POM 中将版本强制为您需要的任何内容。

标签: maven pom.xml artifact transitive-dependency


【解决方案1】:

从您的日志中,您可以找到以下行:

[DEBUG] com.company.xyz:xyz-integration-lib:jar:0.0.1-SNAPSHOT
[DEBUG]    com.company.xyz:xyz-utils:jar:0.0.1-SNAPSHOT:compile
[DEBUG]       commons-codec:commons-codec:jar:1.8:compile
[DEBUG]    javax.mail:mail:jar:1.4:provided
[DEBUG]       javax.activation:activation:jar:1.1.1:provided (version managed from 1.1 by org.jboss.spec:jboss-javaee-6.0:3.0.2.Final)
[DEBUG]    org.apache.commons:commons-lang3:jar:3.3.2:compile
[DEBUG]    junit:junit:jar:4.8.2:test
[DEBUG]    com.thoughtworks.xstream:xstream:jar:1.4.7:compile
[DEBUG]       xmlpull:xmlpull:jar:1.1.3.1:compile
[DEBUG]       xpp3:xpp3_min:jar:1.1.4c:compile
[DEBUG]    joda-time:joda-time:jar:2.4:compile
[DEBUG]    org.assertj:assertj-joda-time:jar:1.1.0:test
[DEBUG]       org.assertj:assertj-core:jar:1.3.0:test
[DEBUG]    org.apache.httpcomponents:httpclient:jar:4.3.5:compile
[DEBUG]       org.apache.httpcomponents:httpcore:jar:4.2.1:compile (version managed from 4.3.2 by org.jboss.as:jboss-as-parent:7.2.0.Final)
[DEBUG]    commons-logging:commons-logging:jar:1.1.3:compile
[DEBUG]    org.slf4j:slf4j-api:jar:1.7.7:compile
[DEBUG]    org.slf4j:slf4j-log4j12:jar:1.7.7:compile
[DEBUG]       log4j:log4j:jar:1.2.17:compile
[DEBUG]    org.mockito:mockito-all:jar:1.9.5:test
[DEBUG]    org.powermock:powermock-module-junit4:jar:1.5.5:test
[DEBUG]       org.powermock:powermock-module-junit4-common:jar:1.5.5:test
[DEBUG]          org.powermock:powermock-core:jar:1.5.5:test
[DEBUG]             org.javassist:javassist:jar:3.18.1-GA:test (version managed from 3.18.2-GA by org.springframework.boot:spring-boot-dependencies:1.1.4.RELEASE)
[DEBUG]          org.powermock:powermock-reflect:jar:1.5.5:test
[DEBUG]             org.objenesis:objenesis:jar:2.1:test
[DEBUG]    org.powermock:powermock-api-mockito:jar:1.5.5:test
[DEBUG]       org.powermock:powermock-api-support:jar:1.5.5:test

您可以看到javassisthttpcore 版本被某些传递依赖项删除,而javax.activation 版本被提升了一个。

当您的多个项目依赖项依赖于同一个库并且定义了对该库不同版本的依赖项时,就会发生这种情况。这可能很烦人,因为通常您无法更改父 POM 或其依赖项如何影响传递依赖项的版本。

来自Maven docs的调解规则如下:

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

“最近的定义”意味着使用的版本将是依赖树中最接近您的项目的版本,例如。如果 A、B 和 C 的依赖项定义为 A -> B -> C -> D 2.0 和 A -> E -> D 1.0,那么在构建 A 时将使用 D 1.0,因为从 A 到 D 通过 E 的路径更短。您可以显式添加一个 A 中对 D 2.0 的依赖以强制使用 D 2.0

但是,您可以自己管理依赖版本。这称为依赖管理,如同一文档所述:

依赖管理 - 这允许项目作者直接 指定遇到工件时要使用的工件版本 在传递依赖或没有版本的依赖中 被指定。在上一节的示例中,依赖项 被直接添加到 A,即使它没有被 A 直接使用。 相反,A 可以在其 dependencyManagement 中包含 D 作为依赖项 部分并直接控制何时或是否使用哪个版本的 D 它曾经被引用过。

因此,您只需添加:

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

到您自己的 POM 中,这将始终覆盖通过依赖中介为传递依赖项定义的任何版本。

【讨论】:

    猜你喜欢
    • 2011-09-10
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 2011-09-12
    • 2011-04-16
    • 2013-05-09
    • 2013-12-04
    • 2011-02-25
    相关资源
    最近更新 更多