问题
I've got a project that depends on a library that I maintain called microservices-common. The microservices-common library in turn depends on commons-codec:1.11
. However, when I attempt to use microservices-common in my project, commons-codec:1.10
ends up on my classpath, and my code fails to compile, because microservices-common is attempting to use a org.apache.commons.codec.digest.DigestUtils
constructor that was added to commons-codec:1.11
, but isn't present in commons-codec:1.10
.
Here's the relevant portion of the dependency tree for microservices-common:
[INFO] com.myproject:microservice-common:jar:1.0-SNAPSHOT
[INFO] +- commons-codec:commons-codec:jar:1.11:compile
[INFO] +- org.apache.httpcomponents:httpclient:jar:4.5.5:compile
[INFO] | \- (commons-codec:commons-codec:jar:1.10:compile - omitted for conflict with 1.11)
[INFO] \- com.myproject:restful:jar:4.1.5-SNAPSHOT:compile
[INFO] +- com.myproject:restful-common:jar:4.1.5-SNAPSHOT:compile
[INFO] | \- (commons-codec:commons-codec:jar:1.8:compile - omitted for conflict with 1.11)
[INFO] \- (commons-codec:commons-codec:jar:1.8:compile - omitted for conflict with 1.11)
If I'm reading the tree correctly, other versions of the commons-codec
dependency, including v1.8 and v1.10 are being ommitted from the classpath in favour of v1.11, which is what I want.
However, if I pull the dependency tree from the perspective of my project that depends on microservices-common, it looks like this:
[INFO] com.myproject:microservice:jar:1.0-SNAPSHOT
[INFO] +- org.apache.httpcomponents:httpasyncclient:jar:4.1.3:compile
[INFO] | \- org.apache.httpcomponents:httpclient:jar:4.5.3:compile
[INFO] | \- (commons-codec:commons-codec:jar:1.10:compile - version managed from 1.11; omitted for duplicate)
[INFO] \- com.myproject:microservice-common:jar:1.0-SNAPSHOT:compile
[INFO] +- commons-codec:commons-codec:jar:1.10:compile
[INFO] \- com.myproject:restful:jar:4.1.5-SNAPSHOT:compile
[INFO] +- com.myproject:restful-common:jar:4.1.5-SNAPSHOT:compile
[INFO] | \- (commons-codec:commons-codec:jar:1.10:compile - version managed from 1.8; omitted for duplicate)
[INFO] \- (commons-codec:commons-codec:jar:1.10:compile - version managed from 1.8; omitted for duplicate)
In this tree, I'm seeing the message "version managed from 1.x; omitted for duplicate". I'm not sure what that means exactly, and, more concerning, line 6 shows that commons-codec:1.10
is what's ending up on my classpath, rather than v1.11, which is what I actually want.
It should be noted that the pom.xml
for com.myproject:microservice-common:jar:1.0-SNAPSHOT
declares the commons-codec:1.11
dependency, so the only places that the commons-codec:1.10
could have come from is either org.apache.httpcomponents:httpclient:jar:4.1.3
or com.myproject:restful:jar:4.1.5-SNAPSHOT
(another common library that I can't get rid of for legacy reasons), but it's not clear to me why that version of the transitive dependency is being selected for inclusion over the version that my microservices-common library declares.
Can anybody explain how dependency selection works when multiple versions of the same library exist in the dependency tree, and why microservices-common appears to select the correct version of the transitive dependency when built in isolation, but my microservices project selects a different version when I build it?
回答1:
Maven chooses the version of the dependency that is nearest in the dependency tree. This is explained very well in the Maven documentation:
"nearest definition" means that the version used will be the closest one to your project in the tree of dependencies, eg. if dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter.
If the dependency is occurring multiple times at the same level, the first declaration wins (since Maven 2.0.9).
The best and established way to ensure using the required version of commons-codec, is to declare dependencyManagement
in your 'microservice' pom (directly under the project
element):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
</dependencyManagement>
Also, make sure you run a recent version of Maven (3.5 recommended).
来源:https://stackoverflow.com/questions/50262265/how-does-maven-choose-the-version-of-a-transitive-dependency-when-two-or-more-ve