在 Gradle 中,依赖项与特定的范围关联,例如编译时或运行时。这些范围由配置表示,每个配置都通过唯一的名称标识。

Gradle 插件通常会向你的项目添加预定义的配置。
例如,当应用 Java 插件时,它会向你的项目添加用于源代码编译 (implementation
)、测试执行 (testImplementation
) 等(api
、compileOnly
、runtimeOnly
等)的配置。
plugins {
`java-library`
}
dependencies {
implementation("org.hibernate:hibernate-core:3.6.7.Final")
testImplementation("junit:junit:4.+")
api("com.google.guava:guava:23.0")
}
plugins {
id 'java-library'
}
dependencies {
implementation 'org.hibernate:hibernate-core:3.6.7.Final'
testImplementation 'junit:junit:4.+'
api 'com.google.guava:guava:23.0'
}
本示例重点介绍了在 Java 项目中声明在 implementation
、testImplementation
和 api
配置上的依赖项。有关详细信息,请参阅Java 插件文档。
可解析配置和可消费配置
配置不仅用于声明依赖项,它们在依赖管理中扮演着多种角色
-
依赖声明角色:定义一组依赖项的配置。
-
消费者角色:用于将依赖项解析为 artifact 的配置。
-
生产者角色:暴露 artifact 以供其他项目消费的配置。
1. 用于声明依赖项的配置(即,可声明配置)
要在你的项目中声明依赖项,你可以使用或创建可声明配置。这些配置有助于组织和分类项目不同部分的依赖项。
例如,要表示对另一个项目的依赖,你会使用像 implementation
这样的可声明配置
dependencies {
// add a project dependency to the implementation configuration
implementation(project(":lib"))
}
dependencies {
// add a project dependency to the implementation configuration
implementation project(":lib")
}
用于声明依赖项的配置定义并管理你的代码在编译或测试等任务中所需的特定库或项目。
2. 用于消费者的配置(即,可解析配置)
要控制依赖项如何在你的项目中解析和使用,你可以使用或创建可解析配置。这些配置定义了你的项目在不同阶段(如编译或运行时)所需的类路径和其他 artifact 集。
例如,implementation
配置声明依赖项,而 compileClasspath
和 runtimeClasspath
是为特定目的设计的可解析配置。解析后,它们分别代表编译和运行时所需的类路径。
configurations {
// declare a resolvable configuration that is going to resolve the compile classpath of the application
resolvable("compileClasspath") {
//isCanBeConsumed = false
//isCanBeDeclared = false
extendsFrom(implementation)
}
}
configurations {
// declare a resolvable configuration that is going to resolve the compile classpath of the application
resolvable("compileClasspath") {
//canBeConsumed = false
//canBeDeclared = false
extendsFrom(implementation)
}
}
可解析配置是可以被解析以生成一组文件或 artifact 的配置。这些配置用于定义构建过程不同阶段(如编译或运行时)的类路径。
3. 用于生产者的配置(即,可消费配置)
可消费配置用于向其他项目暴露 artifact。这些配置定义了你的项目哪些部分可以被其他项目消费,如 API 或运行时依赖项,但不旨在直接在你的项目内部进行解析。
例如,exposedApi
配置是一个可消费配置,它向消费者暴露组件的 API。
configurations {
// a consumable configuration meant for consumers that need the API of this component
consumable("exposedApi") {
//isCanBeResolved = false
//isCanBeDeclared = false
extendsFrom(implementation)
}
}
configurations {
// a consumable configuration meant for consumers that need the API of this component
consumable("exposedApi") {
//canBeResolved = false
//canBeDeclared = false
extendsFrom(implementation)
}
}
库通常提供可消费配置,如 apiElements
(用于编译)和 runtimeElements
(用于运行时依赖项)。这些配置暴露了其他项目消费所需的 artifact,而无需在当前项目内部解析。canBeDeclared
、isCanBeConsumed
和 isCanBeResolved
标志有助于区分这些配置的角色。
配置标志和角色
配置有三个关键标志
-
canBeResolved
: 指示此配置旨在将一组依赖项解析为依赖图。可解析配置不应是可声明或可消费的。 -
canBeConsumed
: 指示此配置旨在向项目外部暴露 artifact。可消费配置不应是可声明或可解析的。 -
canBeDeclared
: 指示此配置旨在声明依赖项。可声明配置不应是可解析或可消费的。
配置只能启用这些标志中的一个。 |
简而言之,配置的角色由 canBeResolved
、canBeConsumed
或 canBeDeclared
标志决定
配置角色 | 可解析 | 可消费 | 可声明 |
---|---|---|---|
依赖范围 |
false |
false |
true |
为特定用途进行解析 |
true |
false |
false |
暴露给消费者 |
false |
true |
false |
遗留,不使用 |
true |
true |
true |
为了向后兼容,这些标志的默认值为 true
,但作为插件作者,你应该始终确定这些标志的正确值,否则可能会意外引入解析错误。
本示例演示了如何在 Gradle 中手动声明核心 Java 配置(通常由Java 插件提供)。
// declare a "configuration" named "implementation"
val implementation by configurations.creating {
isCanBeConsumed = false
isCanBeResolved = false
}
dependencies {
// add a project dependency to the implementation configuration
implementation(project(":lib"))
}
configurations {
// declare a resolvable configuration that is going to resolve the compile classpath of the application
resolvable("compileClasspath") {
//isCanBeConsumed = false
//isCanBeDeclared = false
extendsFrom(implementation)
}
// declare a resolvable configuration that is going to resolve the runtime classpath of the application
resolvable("runtimeClasspath") {
//isCanBeConsumed = false
//isCanBeDeclared = false
extendsFrom(implementation)
}
}
configurations {
// a consumable configuration meant for consumers that need the API of this component
consumable("exposedApi") {
//isCanBeResolved = false
//isCanBeDeclared = false
extendsFrom(implementation)
}
// a consumable configuration meant for consumers that need the implementation of this component
consumable("exposedRuntime") {
//isCanBeResolved = false
//isCanBeDeclared = false
extendsFrom(implementation)
}
}
// declare a "configuration" named "implementation"
configurations {
// declare a "configuration" named "implementation"
implementation {
canBeConsumed = false
canBeResolved = false
}
}
dependencies {
// add a project dependency to the implementation configuration
implementation project(":lib")
}
configurations {
// declare a resolvable configuration that is going to resolve the compile classpath of the application
resolvable("compileClasspath") {
//canBeConsumed = false
//canBeDeclared = false
extendsFrom(implementation)
}
// declare a resolvable configuration that is going to resolve the runtime classpath of the application
resolvable("runtimeClasspath") {
//canBeConsumed = false
//canBeDeclared = false
extendsFrom(implementation)
}
}
configurations {
// a consumable configuration meant for consumers that need the API of this component
consumable("exposedApi") {
//canBeResolved = false
//canBeDeclared = false
extendsFrom(implementation)
}
// a consumable configuration meant for consumers that need the implementation of this component
consumable("exposedRuntime") {
//canBeResolved = false
//canBeDeclared = false
extendsFrom(implementation)
}
}
创建了以下配置
-
implementation
: 用于声明项目依赖项,但既不可消费也不可解析。 -
compileClasspath
+runtimeClasspath
: 可解析配置,从implementation
中收集编译时和运行时依赖项。 -
exposedApi
+exposedRuntime
: 可消费配置,将 artifact(API 和运行时)暴露给其他项目,但不用于内部解析。
此设置模拟了Java 插件中 implementation
、compileClasspath
、runtimeClasspath
、apiElements
和 runtimeElements
配置的行为。
已废弃的配置
过去,一些配置没有定义它们旨在用于的角色。
当配置以非预期的方式使用时,会发出废弃警告。要修复废弃,你需要停止以废弃的角色使用该配置。所需的具体更改取决于配置的使用方式以及是否存在应替代使用的其他配置。
创建自定义配置
你可以定义自定义配置来声明用于特定目的的独立依赖范围。
假设你想生成包含嵌入在 Java 源代码注释中的 AsciiDoc 格式的 Javadoc。通过设置 asciidoclet
配置,你可以让 Gradle 使用 Asciidoclet,从而使你的 Javadoc 任务能够生成具有增强格式选项的 HTML 文档。
val asciidoclet by configurations.creating
dependencies {
asciidoclet("org.asciidoctor:asciidoclet:1.+")
}
tasks.register("configureJavadoc") {
doLast {
tasks.javadoc {
options.doclet = "org.asciidoctor.Asciidoclet"
options.docletpath = asciidoclet.files.toList()
}
}
}
configurations {
asciidoclet
}
dependencies {
asciidoclet 'org.asciidoctor:asciidoclet:1.+'
}
你可以使用 configurations
块管理自定义配置。配置必须有名称,并且可以相互扩展。有关详细信息,请参阅 ConfigurationContainer
API。
配置旨在用于单一角色:声明依赖项、执行解析或定义可消费变体。 |
创建自定义配置有三个主要用例
-
API/实现分离:创建自定义配置以将 API 依赖项(暴露给消费者)与实现依赖项(在编译或运行时内部使用)分开。
-
你可以创建一个
api
配置用于消费者将依赖的库,以及一个implementation
配置用于仅在内部需要的库。api
配置通常被下游项目消费,而implementation
依赖项对消费者隐藏但在内部使用。 -
这种分离确保你的项目在公共 API 和严格的内部机制之间保持清晰的界限。
-
-
可解析配置创建:创建自定义可解析配置以在不同构建阶段解析特定的依赖项集,例如类路径。
-
你可以创建一个
compileClasspath
配置,该配置仅解析编译项目所需的依赖项。类似地,你可以创建一个runtimeClasspath
配置来解析在运行时运行项目所需的依赖项。 -
这允许精细控制哪些依赖项在不同的构建阶段可用,例如编译或测试。
-
-
从依赖配置创建可消费配置:创建自定义可消费配置,以暴露 artifact 或依赖项供其他项目消费,这通常发生在你的项目生成 JAR 等 artifact 时。
-
你可以创建一个
exposedApi
配置,以暴露项目的 API 依赖项供其他项目消费。类似地,可以创建一个runtimeElements
配置,以暴露其他项目所需的运行时依赖项或 artifact。 -
可消费配置确保只有必要的 artifact 或依赖项暴露给消费者。
-
Configuration API 孵化中方法
ConfigurationContainer
API 中的几个孵化中工厂方法——resolvable()
、consumable()
和 dependencyScope()
——可用于简化具有特定角色的配置创建。
这些方法帮助构建作者记录配置的用途,并避免手动设置各种配置标志,从而简化流程并确保一致性
-
resolvable()
: 创建一个旨在解析依赖项的配置。这意味着该配置可用于解析依赖项,但不能被其他项目消费。 -
consumable()
: 创建一个旨在供其他项目消费,但不用于自身解析依赖项的配置。 -
dependencyScope()
: 创建一个建立依赖范围的配置,根据用例设置必要的属性,使其既可以作为消费者,也可以作为提供者。
配置继承
配置可以继承其他配置,创建继承层次结构。
配置使用 Configuration.extendsFrom(Configuration…)
方法形成继承层次结构。配置可以扩展除了分离配置之外的任何其他配置,无论其在构建脚本或插件中如何定义。
避免用不可消费或不可解析的配置分别扩展可消费或可解析的配置。 |
例如,在一个已经使用 JUnit 进行测试的项目中,你可以定义一个名为 smokeTest
的专用配置来运行冒烟测试。每个冒烟测试执行一个 HTTP 请求来验证 Web 服务端点。为了重用现有的测试框架依赖项,smokeTest
配置应扩展自 testImplementation
。这使得冒烟测试可以利用与单元测试相同的依赖项,而无需重复。该配置可以在 build.gradle(.kts)
中声明如下
val smokeTest by configurations.creating {
extendsFrom(configurations.testImplementation.get())
}
dependencies {
testImplementation("junit:junit:4.13")
smokeTest("org.apache.httpcomponents:httpclient:4.5.5")
}
configurations {
smokeTest.extendsFrom testImplementation
}
dependencies {
testImplementation 'junit:junit:4.13'
smokeTest 'org.apache.httpcomponents:httpclient:4.5.5'
}
此设置使 smokeTest
源集能够继承 JUnit 和任何其他测试依赖项,从而更容易定义和执行冒烟测试,同时将其与单元测试分开。
配置只能扩展同一项目中的配置。 |
扩展配置时,新配置会继承
-
依赖项
-
依赖约束
-
排除规则
-
artifact
-
能力
扩展不包括属性。它也不扩展可消费/可解析/可声明状态。
依赖解析
所有依赖解析 API 的入口点是一个可解析的 配置。Java 插件主要使用 compileClasspath
和 runtimeClasspath
配置分别解析用于编译和运行时的 jar 包。
可解析配置旨在启动依赖解析。待解析的依赖项声明在依赖范围配置上。Java 插件使用 api
、implementation
和 runtimeOnly
等依赖范围配置作为可解析配置解析的依赖项来源。
考虑以下示例,它演示了如何声明一组旨在用于解析的配置
此示例使用孵化中的 API。 |
val implementation = configurations.dependencyScope("implementation")
val runtimeClasspath = configurations.resolvable("runtimeClasspath") {
extendsFrom(implementation.get())
}
configurations {
dependencyScope("implementation")
resolvable("runtimeClasspath") {
extendsFrom(implementation)
}
}
可以在 implementation
配置上使用 dependencies 块声明依赖项。有关可声明的依赖项类型以及自定义依赖项声明的各种选项的更多信息,请参阅声明依赖项章节。
dependencies {
implementation("com.google.guava:guava:33.2.1-jre")
}
dependencies {
implementation("com.google.guava:guava:33.2.1-jre")
}
现在我们已经创建了一个用于声明依赖项的依赖范围配置,以及一个用于解析这些依赖项的可解析配置,我们可以使用 Gradle 的依赖解析 API 来访问解析结果。