依赖关系的中央声明

使用版本目录

版本目录是依赖项列表,表示为依赖项坐标,用户在构建脚本中声明依赖项时可以从中选择。

例如,可以从版本目录中选取依赖项坐标,而不是使用字符串表示法声明依赖项:

build.gradle.kts
dependencies {
    implementation(libs.groovy.core)
}
build.gradle
dependencies {
    implementation(libs.groovy.core)
}

在此上下文中,libs是一个目录,groovy表示该目录中可用的依赖项。与直接在构建脚本中声明依赖项相比,版本目录具有许多优点:

  • 对于每个目录,Gradle 都会生成类型安全的访问器,以便您可以在 IDE 中使用自动完成功能轻松添加依赖项。

  • 每个目录对于构建的所有项目都是可见的。它是声明依赖项版本并确保对该版本的更改适用于每个子项目的中心位置。

  • 目录可以声明依赖包,它们是通常一起使用的“依赖组”。

  • 目录可以将依赖项的组和名称与其实际版本分开,并改用版本引用,从而可以在多个依赖项之间共享版本声明。

使用符号添加依赖项的libs.someLib工作方式与直接在构建脚本中硬编码组、工件和版本的工作方式完全相同。

依赖项目录不强制依赖项的版本:与常规依赖项表示法一样,它声明请求的版本或丰富版本。该版本不一定是冲突解决期间选择的版本。

声明版本目录

版本目录可以在settings.gradle(.kts)文件中声明。在上面的示例中,为了groovy通过libs目录提供可用,我们需要将别名与 GAV(组、工件、版本)坐标相关联:

settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            library("groovy-core", "org.codehaus.groovy:groovy:3.0.5")
            library("groovy-json", "org.codehaus.groovy:groovy-json:3.0.5")
            library("groovy-nio", "org.codehaus.groovy:groovy-nio:3.0.5")
            library("commons-lang3", "org.apache.commons", "commons-lang3").version {
                strictly("[3.8, 4.0[")
                prefer("3.9")
            }
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            library('groovy-core', 'org.codehaus.groovy:groovy:3.0.5')
            library('groovy-json', 'org.codehaus.groovy:groovy-json:3.0.5')
            library('groovy-nio', 'org.codehaus.groovy:groovy-nio:3.0.5')
            library('commons-lang3', 'org.apache.commons', 'commons-lang3').version {
                strictly '[3.8, 4.0['
                prefer '3.9'
            }
        }
    }
}

别名及其到类型安全访问器的映射

-别名必须由一系列由短划线(推荐)、下划线(_)或点( )分隔的标识符组成.。标识符本身必须由 ascii 字符组成,最好是小写,最后跟数字。

例如:

  • guava是一个有效的别名

  • groovy-core是一个有效的别名

  • commons-lang3是一个有效的别名

  • androidx.awesome.lib也是一个有效的别名

  • this.#is.not!

然后为每个子组生成类型安全访问器。例如,在名为 的版本目录中给出以下别名libs

guava, groovy-core, groovy-xml, groovy-json,androidx.awesome.lib

我们将生成以下类型安全访问器:

  • libs.guava

  • libs.groovy.core

  • libs.groovy.xml

  • libs.groovy.json

  • libs.androidx.awesome.lib

其中libs前缀来自版本目录名称。

如果您想避免生成子组访问器,我们建议依靠大小写来区分。例如,别名groovyCore,groovyJsongroovyXml将分别映射到libs.groovyCore,libs.groovyJsonlibs.groovyXml访问器。

声明别名时,值得注意的是,任何-,_.字符都可以用作分隔符,但生成的目录将全部标准化为.: 例如,foo-bar作为别名自动转换为foo.bar

有些关键字是保留的,因此不能用作别名。接下来的单词不能用作别名:

  • 扩展

  • 班级

  • 习俗

除此之外,下一个单词不能用作依赖项别名的第一个子组(对于捆绑包、版本和插件,此限制不适用):

  • 捆绑

  • 版本

  • 插件

例如,对于依赖项,别名versions-dependency无效,但versionsDependencydependency-versions有效。

具有相同版本号的依赖项

在声明版本目录的第一个示例中,我们可以看到我们为groovy库的各个组件声明了 3 个别名,并且它们都共享相同的版本号。

我们可以声明一个版本并引用它,而不是重复相同的版本号:

settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            version("groovy", "3.0.5")
            version("checkstyle", "8.37")
            library("groovy-core", "org.codehaus.groovy", "groovy").versionRef("groovy")
            library("groovy-json", "org.codehaus.groovy", "groovy-json").versionRef("groovy")
            library("groovy-nio", "org.codehaus.groovy", "groovy-nio").versionRef("groovy")
            library("commons-lang3", "org.apache.commons", "commons-lang3").version {
                strictly("[3.8, 4.0[")
                prefer("3.9")
            }
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            version('groovy', '3.0.5')
            version('checkstyle', '8.37')
            library('groovy-core', 'org.codehaus.groovy', 'groovy').versionRef('groovy')
            library('groovy-json', 'org.codehaus.groovy', 'groovy-json').versionRef('groovy')
            library('groovy-nio', 'org.codehaus.groovy', 'groovy-nio').versionRef('groovy')
            library('commons-lang3', 'org.apache.commons', 'commons-lang3').version {
                strictly '[3.8, 4.0['
                prefer '3.9'
            }
        }
    }
}

单独声明的版本可以通过类型安全访问器使用,这使得它们比依赖版本可用于更多用例,特别是对于工具:

build.gradle.kts
checkstyle {
    // will use the version declared in the catalog
    toolVersion = libs.versions.checkstyle.get()
}
build.gradle
checkstyle {
    // will use the version declared in the catalog
    toolVersion = libs.versions.checkstyle.get()
}

如果声明版本的别名也是一些更具体别名的前缀,如 和 中libs.versions.zinclibs.versions.zinc.apiinfo则更通用版本的值可通过asProvider()类型安全访问器获得:

build.gradle.kts
scala {
    zincVersion = libs.versions.zinc.asProvider().get()
}
build.gradle
scala {
    zincVersion = libs.versions.zinc.asProvider().get()
}

目录中声明的依赖项通过与其名称相对应的扩展名公开给构建脚本。在上面的示例中,因为在设置中声明的目录名为named ,所以可以通过当前构建的所有构建脚本中的libs名称使用扩展。libs使用以下符号声明依赖关系...​

build.gradle.kts
dependencies {
    implementation(libs.groovy.core)
    implementation(libs.groovy.json)
    implementation(libs.groovy.nio)
}
build.gradle
dependencies {
    implementation libs.groovy.core
    implementation libs.groovy.json
    implementation libs.groovy.nio
}

...​与写作完全相同的效果:

build.gradle.kts
dependencies {
    implementation("org.codehaus.groovy:groovy:3.0.5")
    implementation("org.codehaus.groovy:groovy-json:3.0.5")
    implementation("org.codehaus.groovy:groovy-nio:3.0.5")
}
build.gradle
dependencies {
    implementation 'org.codehaus.groovy:groovy:3.0.5'
    implementation 'org.codehaus.groovy:groovy-json:3.0.5'
    implementation 'org.codehaus.groovy:groovy-nio:3.0.5'
}

目录中声明的版本是丰富版本。请参阅版本目录生成器 API以获取完整的版本声明支持文档。

依赖包

由于某些依赖项经常在不同的项目中系统地一起使用,因此版本目录提供了“依赖项包”的概念。捆绑包基本上是多个依赖项的别名。例如,您可以编写以下代码,而不是像上面那样声明 3 个单独的依赖项:

build.gradle.kts
dependencies {
    implementation(libs.bundles.groovy)
}
build.gradle
dependencies {
    implementation libs.bundles.groovy
}

名为的包groovy需要在目录中声明:

settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            version("groovy", "3.0.5")
            version("checkstyle", "8.37")
            library("groovy-core", "org.codehaus.groovy", "groovy").versionRef("groovy")
            library("groovy-json", "org.codehaus.groovy", "groovy-json").versionRef("groovy")
            library("groovy-nio", "org.codehaus.groovy", "groovy-nio").versionRef("groovy")
            library("commons-lang3", "org.apache.commons", "commons-lang3").version {
                strictly("[3.8, 4.0[")
                prefer("3.9")
            }
            bundle("groovy", listOf("groovy-core", "groovy-json", "groovy-nio"))
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            version('groovy', '3.0.5')
            version('checkstyle', '8.37')
            library('groovy-core', 'org.codehaus.groovy', 'groovy').versionRef('groovy')
            library('groovy-json', 'org.codehaus.groovy', 'groovy-json').versionRef('groovy')
            library('groovy-nio', 'org.codehaus.groovy', 'groovy-nio').versionRef('groovy')
            library('commons-lang3', 'org.apache.commons', 'commons-lang3').version {
                strictly '[3.8, 4.0['
                prefer '3.9'
            }
            bundle('groovy', ['groovy-core', 'groovy-json', 'groovy-nio'])
        }
    }
}

语义再次是等效的:添加单个包相当于添加单独属于该包的所有依赖项。

插件

除了库之外,版本目录还支持声明插件版本。虽然库由其组、工件和版本坐标表示,但 Gradle 插件仅由其 id 和版本标识。因此,它们需要单独声明:

您不能在设置文件或设置插件中使用在版本目录中声明的插件(因为目录是在设置本身中定义的,这将是一个先有鸡还是先有蛋的问题)。
settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            plugin("versions", "com.github.ben-manes.versions").version("0.45.0")
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            plugin('versions', 'com.github.ben-manes.versions').version('0.45.0')
        }
    }
}

然后可以在plugins块中访问该插件,并且可以使用以下方式在构建的任何项目中使用:

build.gradle.kts
plugins {
    `java-library`
    checkstyle
    alias(libs.plugins.versions)
}
build.gradle
plugins {
    id 'java-library'
    id 'checkstyle'
    // Use the plugin `versions` as declared in the `libs` version catalog
    alias(libs.plugins.versions)
}

使用多个目录

除了常规libs目录之外,您还可以通过 API 声明任意数量的目录Settings。这允许您以对您的项目有意义的方式分离多个源中的依赖项声明。

settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("testLibs") {
            val junit5 = version("junit5", "5.7.1")
            library("junit-api", "org.junit.jupiter", "junit-jupiter-api").versionRef(junit5)
            library("junit-engine", "org.junit.jupiter", "junit-jupiter-engine").versionRef(junit5)
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        testLibs {
            def junit5 = version('junit5', '5.7.1')
            library('junit-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef(junit5)
            library('junit-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef(junit5)
        }
    }
}

每个目录都会生成一个应用于所有项目的扩展,以访问其内容。因此,通过选择一个可以减少潜在冲突的名称来减少冲突的机会是有意义的。例如,一个选项是选择一个以 结尾的名称Libs

libs.versions.toml 文件

除了上面的设置 API 之外,Gradle 还提供了一个常规文件来声明目录。如果在根构建的子目录libs.versions.toml中找到文件gradle,则会自动使用该文件的内容声明一个目录。

声明libs.versions.toml文件并不使其成为依赖项的单一事实来源:它是可以声明依赖项的常规位置。一旦开始使用目录,强烈建议在目录中声明所有依赖项,而不是在构建脚本中硬编码组/工件/版本字符串。请注意,插件可能会添加依赖项,这些依赖项是在此文件外部定义的依赖项。

就像src/main/java查找 Java 源代码的约定一样,它不会阻止声明其他源目录(在构建脚本或插件中),文件的存在libs.versions.toml不会阻止在其他地方声明依赖项。

然而,该文件的存在确实表明大多数依赖项(如果不是全部)将在此文件中声明。因此,对于大多数用户来说,更新依赖项版本应该只包含更改此文件中的一行。

默认情况下,该libs.versions.toml文件将作为目录的输入libs。可以更改默认目录的名称,例如,如果您已经有同名的扩展:

settings.gradle.kts
dependencyResolutionManagement {
    defaultLibrariesExtensionName = "projectLibs"
}
settings.gradle
dependencyResolutionManagement {
    defaultLibrariesExtensionName = 'projectLibs'
}

版本目录TOML文件格式

TOML文件由 4 个主要部分组成:

  • [versions]部分用于声明可以被依赖项引用的版本

  • [libraries]部分用于声明坐标的别名

  • [bundles]部分用于声明依赖包

  • [plugins]部分用于声明插件

例如:

libs.versions.toml 文件
[versions]
groovy = "3.0.5"
checkstyle = "8.37"

[libraries]
groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" }
groovy-json = { module = "org.codehaus.groovy:groovy-json", version.ref = "groovy" }
groovy-nio = { module = "org.codehaus.groovy:groovy-nio", version.ref = "groovy" }
commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0[", prefer="3.9" } }

[bundles]
groovy = ["groovy-core", "groovy-json", "groovy-nio"]

[plugins]
versions = { id = "com.github.ben-manes.versions", version = "0.45.0" }

版本可以声明为单个字符串(在这种情况下它们被解释为必需版本),也可以声明为丰富版本

[versions]
my-lib = { strictly = "[1.0, 2.0[", prefer = "1.2" }

版本声明支持的成员有:

依赖项声明可以声明为简单字符串(在这种情况下它们被解释为group:artifact:version坐标),也可以将版本声明与组和名称分开:

对于别名,别名部分中描述的规则及其到类型安全访问器的映射也适用。
不同的依赖符号
[versions]
common = "1.4"

[libraries]
my-lib = "com.mycompany:mylib:1.4"
my-other-lib = { module = "com.mycompany:other", version = "1.4" }
my-other-lib2 = { group = "com.mycompany", name = "alternate", version = "1.4" }
mylib-full-format = { group = "com.mycompany", name = "alternate", version = { require = "1.4" } }

[plugins]
short-notation = "some.plugin.id:1.4"
long-notation = { id = "some.plugin.id", version = "1.4" }
reference-notation = { id = "some.plugin.id", version.ref = "common" }

如果您想引用该[versions]部分中声明的版本,您应该使用以下version.ref属性:

[versions]
some = "1.4"

[libraries]
my-lib = { group = "com.mycompany", name="mylib", version.ref="some" }

TOML 文件格式非常宽松,允许您编写“点式”属性作为完整对象声明的快捷方式。例如,这个:

a.b.c="d"

相当于:

a.b = { c = "d" }

或者

a = { b = { c = "d" } }

有关详细信息,请参阅TOML 规范

类型不安全 API

可以通过类型不安全的 API 访问版本目录。此 API 在生成的访问器不可用的情况下可用。它可以通过版本目录扩展来访问:

build.gradle.kts
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
println("Library aliases: ${versionCatalog.libraryAliases}")
dependencies {
    versionCatalog.findLibrary("groovy-json").ifPresent {
        implementation(it)
    }
}
build.gradle
def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs")
println "Library aliases: ${versionCatalog.libraryAliases}"
dependencies {
    versionCatalog.findLibrary("groovy-json").ifPresent {
        implementation(it)
    }
}

检查版本目录 API以了解所有支持的方法。

共享目录

版本目录用于单个构建(可能是多项目构建),但也可以在构建之间共享。例如,组织可能想要创建来自不同团队的不同项目可以使用的依赖项目录。

从 TOML 文件导入目录

版本目录构建器 API支持包含外部文件中的模型。如果需要的话,这使得可以重用主构建的目录buildSrc。例如,该buildSrc/settings.gradle(.kts)文件可以使用以下命令包含该文件:

settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

使用VersionCatalogBu​​ilder.from(Object dependencyNotation)方法时,仅接受单个文件。这意味着像Project.files(java.lang.Object…​)这样的符号必须引用单个文件,否则构建将失败。

如果需要更复杂的结构(从多个文件导入的版本目录),建议使用基于代码的方法,而不是 TOML 文件。

因此,该技术可用于声明来自不同文件的多个目录:

settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        // declares an additional catalog, named 'testLibs', from the 'test-libs.versions.toml' file
        create("testLibs") {
            from(files("gradle/test-libs.versions.toml"))
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        // declares an additional catalog, named 'testLibs', from the 'test-libs.versions.toml' file
        testLibs {
            from(files('gradle/test-libs.versions.toml'))
        }
    }
}

版本目录插件

虽然从本地文件导入目录很方便,但它并不能解决在组织中或外部消费者共享目录的问题。共享目录的一种选择是编写一个设置插件,将其发布到 Gradle 插件门户或内部存储库上,并让使用者在其设置文件上应用该插件。

或者,Gradle 提供版本目录插件,它提供声明然后发布目录的功能。

为此,您需要应用该version-catalog插件:

build.gradle.kts
plugins {
    `version-catalog`
    `maven-publish`
}
build.gradle
plugins {
    id 'version-catalog'
    id 'maven-publish'
}

然后,该插件将公开可用于声明目录的目录扩展:

build.gradle.kts
catalog {
    // declare the aliases, bundles and versions in this block
    versionCatalog {
        library("my-lib", "com.mycompany:mylib:1.2")
    }
}
build.gradle
catalog {
    // declare the aliases, bundles and versions in this block
    versionCatalog {
        library('my-lib', 'com.mycompany:mylib:1.2')
    }
}

maven-publish然后可以通过应用或ivy-publish插件并配置发布以使用该组件来发布这样的目录versionCatalog

build.gradle.kts
publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["versionCatalog"])
        }
    }
}
build.gradle
publishing {
    publications {
        maven(MavenPublication) {
            from components.versionCatalog
        }
    }
}

发布此类项目时,libs.versions.toml将自动生成(并上传)一个文件,然后可以从其他 Gradle 构建中使用该文件。

导入已发布的目录

版本目录插件生成的目录可以通过设置 API 导入:

settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from("com.mycompany:catalog:1.0")
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            from("com.mycompany:catalog:1.0")
        }
    }
}

覆盖目录版本

如果目录声明了版本,您可以在导入目录时覆盖该版本:

settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("amendedLibs") {
            from("com.mycompany:catalog:1.0")
            // overwrite the "groovy" version declared in the imported catalog
            version("groovy", "3.0.6")
        }
    }
}
settings.gradle
dependencyResolutionManagement {
    versionCatalogs {
        amendedLibs {
            from("com.mycompany:catalog:1.0")
            // overwrite the "groovy" version declared in the imported catalog
            version("groovy", "3.0.6")
        }
    }
}

在上面的示例中,任何使用groovy版本作为参考的依赖项都将自动更新为使用3.0.6.

同样,覆盖版本并不意味着实际解析的依赖项版本将相同:这只会更改导入的内容,也就是说声明依赖项时使用的内容。实际版本将遵循传统的冲突解决方案(如果有)。

使用平台来控制传递版本

平台是一种特殊的软件组件可用于控制传递依赖版本。在大多数情况下,它完全由依赖项约束组成,这些依赖项约束将建议依赖项版本或强制执行某些版本。因此,每当您需要在项目之间共享依赖项版本时,这都是一个完美的工具。在这种情况下,项目通常会这样组织:

  • 一个platform项目,它定义了不同子项目中发现的各种依赖项的约束

  • 一些依赖于平台并声明无版本依赖关系的子项目

在Java生态系统中,Gradle为此提供了一个插件。

发现Gradle 原生支持的以 Maven BOM 形式发布的平台也很常见。

使用关键字创建对平台的依赖关系platform

build.gradle.kts
dependencies {
    // get recommended versions from the platform project
    api(platform(project(":platform")))
    // no version required
    api("commons-httpclient:commons-httpclient")
}
build.gradle
dependencies {
    // get recommended versions from the platform project
    api platform(project(':platform'))
    // no version required
    api 'commons-httpclient:commons-httpclient'
}

platform表示法是一种简写表示法,实际上在幕后执行了多种操作:

  • 它将org.gradle.category 属性设置为platform,这意味着 Gradle 将选择依赖项的平台组件。

  • 它默认设置endorsStrictVersions行为,这意味着如果平台声明严格依赖关系,它们将被强制执行。

这意味着默认情况下,对平台的依赖会触发该平台中定义的所有严格版本的继承,这对于平台作者确保所有消费者尊重他们在依赖项版本方面的决定非常有用。可以通过显式调用该方法来关闭此功能doNotEndorseStrictVersions

导入 Maven BOM

Gradle 提供对导入物料清单 (BOM) 文件的支持,这些文件是用于控制直接依赖项和传递依赖项的依赖项版本的有效.pom文件。 <dependencyManagement>Gradle 中的 BOM 支持的工作方式与<scope>import</scope>依赖 Maven 中的 BOM 时的使用类似。然而,在 Gradle 中,这是通过 BOM 上的常规依赖项声明来完成的:

build.gradle.kts
dependencies {
    // import a BOM
    implementation(platform("org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE"))

    // define dependencies without versions
    implementation("com.google.code.gson:gson")
    implementation("dom4j:dom4j")
}
build.gradle
dependencies {
    // import a BOM
    implementation platform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE')

    // define dependencies without versions
    implementation 'com.google.code.gson:gson'
    implementation 'dom4j:dom4j'
}

在示例中,gson和的版本dom4j由 Spring Boot BOM 提供。这样,如果您正在为像 Spring Boot 这样的平台进行开发,则不必自己声明任何版本,而是可以依赖平台提供的版本。

Gradle 对待 BOM 块中的所有条目的方式与Gradle 的依赖关系约束<dependencyManagement>类似。这意味着块中定义的任何版本都可能影响依赖项解析结果。为了符合 BOM 的资格,需要设置一个文件。<dependencyManagement>.pom<packaging>pom</packaging>

然而,BOM 通常不仅提供版本作为建议,而且还提供一种覆盖图中发现的任何其他版本的方法。您可以在导入 BOM 时使用enforcedPlatform关键字而不是 来启用此行为:platform

build.gradle.kts
dependencies {
    // import a BOM. The versions used in this file will override any other version found in the graph
    implementation(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE"))

    // define dependencies without versions
    implementation("com.google.code.gson:gson")
    implementation("dom4j:dom4j")

    // this version will be overridden by the one found in the BOM
    implementation("org.codehaus.groovy:groovy:1.8.6")
}
build.gradle
dependencies {
    // import a BOM. The versions used in this file will override any other version found in the graph
    implementation enforcedPlatform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE')

    // define dependencies without versions
    implementation 'com.google.code.gson:gson'
    implementation 'dom4j:dom4j'

    // this version will be overridden by the one found in the BOM
    implementation 'org.codehaus.groovy:groovy:1.8.6'
}

enforcedPlatform如果您的软件组件可以被其他人使用,则需要谨慎考虑使用。该声明实际上是可传递的,因此将适用于消费者的依赖图。不幸的是,exclude如果他们碰巧不同意其中一种强制版本,他们将不得不使用。相反,如果您的可重用软件组件对某些第三方依赖项版本有强烈的意见,请考虑使用带有strictly.

我应该使用平台还是目录?

由于平台和目录都讨论依赖项版本,并且都可以用于在项目中共享依赖项版本,因此可能会出现关于使用什么以及其中一个是否优于另一个的混淆。

简而言之,您应该:

  • 使用目录仅定义项目的依赖项及其版本并生成类型安全的访问器

  • 使用平台将版本应用于依赖关系图并影响依赖关系解析

目录有助于集中依赖项版本,顾名思义,它只是您可以从中选择的依赖项目录。在所有情况下,我们建议使用它来声明依赖项的坐标。 Gradle 将使用它来生成类型安全的访问器,为外部依赖项提供简写符号,并允许在不同项目之间轻松共享这些坐标。使用目录不会对下游消费者产生任何后果:它对他们来说是透明的。

平台是一个更重量级的构造:它是依赖图的组件,就像任何其他库一样。如果您依赖于某个平台,那么该平台本身就是图中的一个组件。这尤其意味着:

  • 平台中定义的约束会影响传递依赖项,而不仅仅是项目的直接依赖项。

  • 平台是版本化的,图中的传递依赖项可能依赖于平台的不同版本,从而导致各种依赖项升级。

  • 平台可以将组件捆绑在一起,特别是可以用作对齐版本的构造。

  • 对平台的依赖项由依赖项的使用者“继承”:这意味着对平台的依赖项可以影响您的使用者将使用哪些版本的库,即使您不直接或间接依赖组件平台参考。

总之,使用目录始终是一种良好的工程实践,因为它集中了通用定义,允许共享依赖项版本或插件版本,但它是构建的“实现细节”:它对消费者和未使用的元素不可见。目录被忽略。

平台旨在影响依赖关系解析图,例如通过添加对传递依赖关系的约束:它是构建依赖关系图并影响解析结果的解决方案。

实际上,您的项目既可以使用目录,又可以声明一个本身使用该目录的平台:

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

dependencies {
    constraints {
        api(libs.mylib)
    }
}
build.gradle
plugins {
    id 'java-platform'
}

dependencies {
    constraints {
        api(libs.mylib)
    }
}