2

I have a parent project contains a dozen child projects, one of the child projects use org.apache.httpcomponents:httpclient:jar:4.3.5, which depends on org.apache.httpcomponents:httpcore:jar:4.3.2.

However, the result version of httpcore is resolved to 4.2.1 instead of 4.3.2.

The following is an extraction of the output when running dependency:tree with debug option checked in Eclipse:

...
[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).
...

It just shows replacement=org.apache.httpcomponents:httpcore:jar:4.2.1, but it tells nothing about the reason of the replacement. The parent project's pom.xml uses quite a lot dependencies and even though I could try to remove those dependencies one by one and check the result, it would be quite time consuming. Is there any more effective way to debug the artifact replacement?


Here is almost the full log of the dependency:tree from Eclipse with debug option checked.

4

1 回答 1

6

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

[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

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

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

来自Maven 文档的中介规则如下:

依赖中介——这决定了当遇到工件的多个版本时将使用哪个版本的依赖。目前,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 可以将 D 作为依赖项包含在其 dependencyManagement 部分中,并直接控制何时或是否使用 D 的哪个版本,它曾经被引用过。

因此,您只需添加:

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

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

于 2014-10-11T18:38:28.113 回答