Gradle 中是否共享子依赖项?
Are sub-dependencies shared in Gradle?
如果库 L
是 X
和 Y
项目的依赖项,并且您的 MainModule
有:
implementation X
implementation Y
X
和 Y
共享相同的 L
吗?如果 X
需要与 Y
不同的 L
版本怎么办?
它在 Gradle 文档中有清楚的描述:TL;DR 在版本冲突的情况下,默认是 select 具有最高版本的依赖项。但请注意 version conflict resolution can be customized.
Version conflict resolution
A version conflict occurs when two components:
Depend on the same module, let’s say com.google.guava:guava
But on different versions, let’s say 20.0
and 25.1-android
Our project itself depends on com.google.guava:guava:20.0
Our project also depends on com.google.inject:guice:4.2.2
which itself depends on com.google.guava:guava:25.1-android
Resolution strategy
Given the conflict above, there exist multiple ways to handle it, either by selecting a version or failing the resolution. Different tools that handle dependency management have different ways of handling these type of conflicts.
Apache Maven uses a nearest first strategy.
Maven will take the shortest path to a dependency and use that version. In case there are multiple paths of the same length, the first one wins.
This means that in the example above, the version of guava
will be 20.0
because the direct dependency is closer than the guice
dependency.
The main drawback of this method is that it is ordering dependent. Keeping order in a very large graph can be a challenge. For example, what if the new version of a dependency ends up having its own dependency declarations in a different order than the previous version?
With Maven, this could have unwanted impact on resolved versions.
Apache Ivy is a very flexible dependency management tooling. It offers the possibility to customize dependency resolution, including conflict resolution.
This flexibility comes with the price of making it hard to reason about.
Gradle will consider all requested versions, wherever they appear in the dependency graph. Out of these versions, it will select the highest one.
As you have seen, Gradle supports a concept of rich version declaration, so what is the highest version depends on the way versions were declared:
If no ranges are involved, then the highest version that is not rejected will be selected.
- If a version declared as
strictly
is lower than that version, selection will fail.
If ranges are involved:
If there is a non range version that falls within the specified ranges or is higher than their upper bound, it will be selected.
If there are only ranges, the highest existing version of the range with the highest upper bound will be selected.
If a version declared as strictly
is lower than that version, selection will fail.
Note that in the case where ranges come into play, Gradle requires metadata to determine which versions do exist for the considered range. This causes an intermediate lookup for metadata, as described in How Gradle retrieves dependency metadata?.
-- https://docs.gradle.org/current/userguide/dependency_resolution.html#sec:version-conflict
如果库 L
是 X
和 Y
项目的依赖项,并且您的 MainModule
有:
implementation X
implementation Y
X
和 Y
共享相同的 L
吗?如果 X
需要与 Y
不同的 L
版本怎么办?
它在 Gradle 文档中有清楚的描述:TL;DR 在版本冲突的情况下,默认是 select 具有最高版本的依赖项。但请注意 version conflict resolution can be customized.
Version conflict resolution
A version conflict occurs when two components:
Depend on the same module, let’s say
com.google.guava:guava
But on different versions, let’s say
20.0
and25.1-android
Our project itself depends on
com.google.guava:guava:20.0
Our project also depends on
com.google.inject:guice:4.2.2
which itself depends oncom.google.guava:guava:25.1-android
Resolution strategy
Given the conflict above, there exist multiple ways to handle it, either by selecting a version or failing the resolution. Different tools that handle dependency management have different ways of handling these type of conflicts.
Apache Maven uses a nearest first strategy.
Maven will take the shortest path to a dependency and use that version. In case there are multiple paths of the same length, the first one wins.
This means that in the example above, the version of
guava
will be20.0
because the direct dependency is closer than theguice
dependency.The main drawback of this method is that it is ordering dependent. Keeping order in a very large graph can be a challenge. For example, what if the new version of a dependency ends up having its own dependency declarations in a different order than the previous version?
With Maven, this could have unwanted impact on resolved versions.
Apache Ivy is a very flexible dependency management tooling. It offers the possibility to customize dependency resolution, including conflict resolution.
This flexibility comes with the price of making it hard to reason about.
Gradle will consider all requested versions, wherever they appear in the dependency graph. Out of these versions, it will select the highest one.
As you have seen, Gradle supports a concept of rich version declaration, so what is the highest version depends on the way versions were declared:
If no ranges are involved, then the highest version that is not rejected will be selected.
- If a version declared as
strictly
is lower than that version, selection will fail.If ranges are involved:
If there is a non range version that falls within the specified ranges or is higher than their upper bound, it will be selected.
If there are only ranges, the highest existing version of the range with the highest upper bound will be selected.
If a version declared as
strictly
is lower than that version, selection will fail.Note that in the case where ranges come into play, Gradle requires metadata to determine which versions do exist for the considered range. This causes an intermediate lookup for metadata, as described in How Gradle retrieves dependency metadata?.
-- https://docs.gradle.org/current/userguide/dependency_resolution.html#sec:version-conflict