平台和版本目录都有助于在项目中管理依赖版本,但它们服务于不同的目的,并且对依赖解析有不同的影响

版本目录

  • 目的: 版本目录集中和标准化依赖坐标(group, name, version),并在构建脚本中提供类型安全的访问器,使依赖更易于管理。

  • 对依赖图的影响: 版本目录直接影响依赖解析。目录中定义的版本必须在dependencies块中显式引用,一旦引用,它们的行为与任何本地声明的依赖相同。此外,目录的内容对下游消费者透明,这意味着消费者无法识别依赖是本地声明的还是来自目录。

libs.versions.toml
[libraries]
mylib = { group = "com.example", name = "mylib", version = "1.0.0" }

平台

  • 目的: 平台是依赖图中的一个模块,用于强制或对齐依赖(包括传递性依赖)的版本。它影响依赖解析,并确保不同模块间的版本一致性。

  • 对依赖图的影响: 平台应用强制依赖使用其声明的版本(即使本地声明时未指定版本)。平台中的这些版本通过依赖图传播,影响传递性依赖和下游消费者。它们是依赖图的正式组成部分,并可以在解析过程中决定最终选择的版本。

build.gradle.kts
plugins {
    `java-platform`
}

dependencies {
    constraints {
        api("com.example:mylib:2.0.0")
    }
}

在平台中使用版本目录

即使版本目录为某个依赖定义了版本,如果其他组件(例如平台或传递性依赖)建议使用不同版本,Gradle在解析时可能会选择不同的版本(除非使用了enforcedPlatform)。

例如,版本目录可能将mylib定义为版本1.0.0,但如果平台强制使用2.0.0,Gradle将选择版本2.0.0

为了确保一致的版本对齐,一种好的方法是使用版本目录来定义依赖版本,并结合平台来强制执行这些版本。

版本目录

gradle/libs.versions.toml
[versions]
junit-jupiter = "5.10.3"

[libraries]
guava = { module = "com.google.guava:guava"}
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
junit-jupiter-launcher = { module = "org.junit.platform:junit-platform-launcher" }

平台

platform/build.gradle.kts
plugins {
    `java-platform`
}

javaPlatform {
    allowDependencies()
}

dependencies {
    constraints {
        api("org.junit.jupiter:junit-jupiter:5.11.1") // Enforcing specific version
        api("com.google.guava:guava:[33.1.0-jre,)") // Enforcing version range
    }
}
platform/build.gradle
plugins {
    id 'java-platform'
}

javaPlatform {
    allowDependencies()
}

dependencies {
    constraints {
        api 'org.junit.jupiter:junit-jupiter:5.11.1' // Enforcing specific version
        api 'com.google.guava:guava:[33.1.0-jre,)' // Enforcing version range
    }
}

消费者

consumer/build.gradle.kts
dependencies {
    // Platform
    implementation(platform(project(":platform")))
    // Catalog
    testImplementation(libs.junit.jupiter)
    testRuntimeOnly(libs.junit.jupiter.launcher)
    implementation(libs.guava)
}
consumer/build.gradle
dependencies {
    // Platform
    implementation platform(project(":platform"))
    // Catalog
    testImplementation libs.junit.jupiter
    testRuntimeOnly libs.junit.jupiter.launcher
    implementation libs.guava
}

使用版本目录和平台的最佳实践

  1. 使用版本目录定义和跨项目共享依赖坐标。它们使依赖声明更一致且易于管理,但不保证版本对齐。

  2. 使用平台当你需要影响或强制模块间的版本对齐时。平台确保依赖解析到期望的版本,特别是在大型或多模块项目中。