依赖版本对齐确保属于同一逻辑组(一个平台)的不同模块在依赖图中统一使用相同版本。
为什么会出现模块版本不一致?
Gradle支持对齐属于同一平台的模块版本。例如,组件的API和实现模块应该使用相同版本。
然而,由于传递性依赖解析,同一平台内的模块最终可能使用不同版本,从而导致潜在的兼容性问题。
考虑以下示例,您的项目同时依赖于jackson-databind
和vert.x
dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind:2.8.9")
implementation("io.vertx:vertx-core:3.5.3")
}
dependencies {
implementation("org.apache.commons:commons-lang3:3.2")
constraints {
implementation("org.apache.commons:commons-lang3:3.1") {
because("Version 1.3 introduces breaking changes not yet handled")
}
}
}
依赖解析可能导致
-
jackson-core
→2.9.5
(vertx-core
所需) -
jackson-databind
→2.9.5
(通过冲突解析) -
jackson-annotations
→2.9.0
(jackson-databind:2.9.5
的依赖)
问题在于Vert.x
(3.5.0
)使用了旧版本的Jackson
(2.9.0
),但显式依赖(2.9.5
)强制Gradle将Vert.x
的Jackson
依赖从2.9.0
升级到2.9.5
> Task :dependencies
------------------------------------------------------------
Root project 'how_to_align_dependency_versions'
------------------------------------------------------------
runtimeClasspath - Runtime classpath of source set 'main'.
+--- com.fasterxml.jackson.core:jackson-databind:2.8.9 -> 2.9.5
| +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
| \--- com.fasterxml.jackson.core:jackson-core:2.9.5
\--- io.vertx:vertx-core:3.5.3
+--- io.netty:netty-common:4.1.19.Final
...
| \--- io.netty:netty-transport:4.1.19.Final (*)
+--- com.fasterxml.jackson.core:jackson-core:2.9.5
\--- com.fasterxml.jackson.core:jackson-databind:2.9.5 (*)
这种不匹配可能导致不兼容问题和意外故障。
Gradle通过平台提供依赖版本对齐,确保相关模块使用一致版本。
选项1:使用已发布的平台
如果公共平台(也称为BOM)可用,则将其作为平台导入
dependencies {
implementation(platform("com.fasterxml.jackson:jackson-bom:2.8.9"))
implementation("com.fasterxml.jackson.core:jackson-databind:2.8.9")
implementation("io.vertx:vertx-core:3.5.3")
}
运行./gradlew dependencies --configuration runtimeClasspath
将显示对齐的依赖项
> Task :dependencies
------------------------------------------------------------
Root project 'how_to_align_dependency_versions'
------------------------------------------------------------
runtimeClasspath - Runtime classpath of source set 'main'.
+--- com.fasterxml.jackson:jackson-bom:2.8.9
| +--- com.fasterxml.jackson.core:jackson-databind:2.8.9 -> 2.9.5 (c)
| +--- com.fasterxml.jackson.core:jackson-core:2.8.9 -> 2.9.5 (c)
| \--- com.fasterxml.jackson.core:jackson-annotations:2.8.0 -> 2.9.0 (c)
+--- com.fasterxml.jackson.core:jackson-databind:2.8.9 -> 2.9.5
| +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
| \--- com.fasterxml.jackson.core:jackson-core:2.9.5
\--- io.vertx:vertx-core:3.5.3
+--- io.netty:netty-common:4.1.19.Final
...
| \--- io.netty:netty-transport:4.1.19.Final (*)
+--- com.fasterxml.jackson.core:jackson-core:2.9.5
\--- com.fasterxml.jackson.core:jackson-databind:2.9.5 (*)
选项2:创建虚拟平台
如果不存在公共BOM,则可以创建虚拟平台。
在这种情况下,Gradle会根据正在使用的模块动态构建平台。为此,您必须定义组件元数据规则
abstract class JacksonAlignmentRule : ComponentMetadataRule {
override fun execute(ctx: ComponentMetadataContext) {
ctx.details.run {
if (id.group.startsWith("com.fasterxml.jackson")) {
belongsTo("com.fasterxml.jackson:jackson-virtual-platform:${id.version}")
}
}
}
}
dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind:2.8.9")
implementation("io.vertx:vertx-core:3.5.3")
dependencies {
components.all<JacksonAlignmentRule>()
}
}
这确保了所有Jackson模块对齐到相同版本,即使是传递性引入的。
运行./gradlew dependencies --configuration runtimeClasspath
将显示对齐的依赖项
> Task :dependencies
------------------------------------------------------------
Root project 'how_to_align_dependency_versions'
------------------------------------------------------------
runtimeClasspath - Runtime classpath of source set 'main'.
+--- com.fasterxml.jackson.core:jackson-databind:2.8.9 -> 2.9.5
| +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0 -> 2.9.5
| \--- com.fasterxml.jackson.core:jackson-core:2.9.5
\--- io.vertx:vertx-core:3.5.3
+--- io.netty:netty-common:4.1.19.Final
...
| \--- io.netty:netty-transport:4.1.19.Final (*)
+--- com.fasterxml.jackson.core:jackson-core:2.9.5
\--- com.fasterxml.jackson.core:jackson-databind:2.9.5 (*)
选项3:使用Java插件
Gradle原生支持版本对齐,使用Java平台插件。
当项目有多个版本同步的模块(例如,lib
、utils
、core
)时,使用混合版本(例如,core:1.0
和lib:1.1
)可能导致运行时问题或不兼容性。
考虑一个具有三个模块的项目
-
lib
-
utils
-
core
(依赖于lib
和utils
)
消费者项目声明
-
core
版本1.0 -
lib
版本1.1
默认情况下,Gradle选择core:1.0
和lib:1.1
,导致版本不对齐。
要解决此问题,引入一个强制约束的平台模块
plugins {
`java-platform`
}
dependencies {
// The platform declares constraints on all components that
// require alignment
constraints {
api(project(":core"))
api(project(":lib"))
api(project(":utils"))
}
}
plugins {
id 'java-platform'
}
dependencies {
// The platform declares constraints on all components that
// require alignment
constraints {
api(project(":core"))
api(project(":lib"))
api(project(":utils"))
}
}
每个模块都应声明对平台的依赖
dependencies {
// Each project has a dependency on the platform
api(platform(project(":platform")))
// And any additional dependency required
implementation(project(":lib"))
implementation(project(":utils"))
}
dependencies {
// Each project has a dependency on the platform
api(platform(project(":platform")))
// And any additional dependency required
implementation(project(":lib"))
implementation(project(":utils"))
}
这确保所有依赖(core
、lib
和utils
)都能一致地解析到版本1.1
。
总结
通过使用平台和BOM,Gradle可确保一致的依赖版本,避免兼容性问题。当不存在已发布的BOM时,虚拟平台允许手动对齐依赖。