学习项目依赖和 Gradle 依赖管理的基础知识。

在本节中,您将

  • 理解项目依赖

  • 检查项目依赖

  • 使用 Build Scan 分析依赖

  • 更新项目依赖

  • 理解传递性依赖

  • 添加版本目录

步骤 0. 开始之前

  1. 您已在第一部分中初始化了 Java 应用。

  2. 您在第二部分中运行了几个任务。

步骤 1. 理解版本目录

在 Gradle 中,您的 build 脚本中的 dependencies {} 块是您声明项目工作所需的外部库的地方。

此块内的每一行都告诉 Gradle 两件事

  1. 依赖项是什么(例如 Guava 或 JUnit)

  2. 如何使用它(用于生产代码、测试代码等)

例如

dependencies {
    implementation("com.google.guava:guava:32.1.2-jre") (1)
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") (2)
}
1 implementation(guava):这意味着您的主应用代码依赖于 Guava 库。Gradle 将从仓库下载它,并将其包含在编译和运行时类路径中。
2 testImplementation(jupiter):这意味着您的测试代码依赖于 JUnit Jupiter(一个测试库)。它只在测试期间可用,不会包含在最终打包的应用中。

第一部分中,Gradle init 创建了一个使用版本目录的项目。

版本目录是一个中心文件,它定义了您可以在整个构建中使用的库版本和别名。它有助于在子项目之间保持依赖项的一致性,并避免重复版本号。

版本目录位于 gradle/libs.versions.toml

gradle/libs.versions.toml
[versions]
guava = "33.3.1-jre"
junit-jupiter = "5.11.3"

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

定义后,您可以使用 libs 访问器在 build.gradle(.kts) 文件中引用这些库。这就是为什么我们的 build 脚本实际上看起来像这样

app/build.gradle.kts
dependencies {  (2)
    // Use JUnit Jupiter for testing.
    testImplementation(libs.junit.jupiter)

    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    // This dependency is used by the application.
    implementation(libs.guava)
}
app/build.gradle
dependencies {  (2)
    // Use JUnit Jupiter for testing.
    testImplementation libs.junit.jupiter

    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    // This dependency is used by the application.
    implementation libs.guava
}
使用 libs.junit.jupiter 语法是因为该键包含连字符,这是一个特殊字符。

版本目录相比直接在 build 脚本中声明依赖项提供了许多优势

  • Gradle 从目录生成类型安全的访问器,以便您可以使用 IDE 中的自动补全轻松添加依赖项。

  • 它是一个中心位置,用于声明依赖项的版本,这样任何更改都将应用于每个子项目。

步骤 2. 理解项目依赖

Gradle 为依赖管理和自动化提供了出色的支持。

让我们再看一眼我们的 build 脚本,特别是以下部分

app/build.gradle.kts
repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {  (2)
    // Use JUnit Jupiter for testing.
    testImplementation(libs.junit.jupiter)

    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    // This dependency is used by the application.
    implementation(libs.guava)
}
app/build.gradle
repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {  (2)
    // Use JUnit Jupiter for testing.
    testImplementation libs.junit.jupiter

    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    // This dependency is used by the application.
    implementation libs.guava
}

Gradle 依赖管理中的一些关键概念包括

仓库

依赖项的来源 → 在我们的应用中是 mavenCentral()

依赖项

通过配置类型声明的依赖项 → 在我们的应用中是 libs.junit.jupiterlibs.guava

Maven Central 仓库是 Maven 社区提供并由 Sonatype 支持的 jar 文件、插件和库的集合。它是事实上的 Java 公共 Artifact 存储库,并被许多构建系统使用。

Gradle 需要特定的信息,称为 GAV 坐标,来定位和下载依赖项。GAV 代表 Group、Artifact 和 Version(Group、Artifact 和 版本)—— 这是唯一标识仓库中库的三部分信息。让我们看看 libs.guavalibs.junit.jupiter

描述 com.google.guava:guava:33.3.1-jre org.junit.jupiter:junit-jupiter-api:5.11.3

Group

组织的标识符

com.google.guava

org.junit.jupiter

Artifact (名称)

依赖项标识符

guava

junit-jupiter-api

版本

要导入的版本号

33.3.1-jre

5.11.3

步骤 3. 理解传递性依赖

传递性依赖 是依赖项的依赖项。

我们的 guava 依赖项要工作,它需要一个名为 failureaccess 的库。因此,failureaccess 是该项目的传递性依赖。

步骤 4. 查看项目依赖

您可以使用 ./gradlew :app:dependencies 命令在终端中查看您的依赖树

$ ./gradlew :app:dependencies

> Task :app:dependencies

------------------------------------------------------------
Project ':app'
------------------------------------------------------------

...

runtimeClasspath - Runtime classpath of source set 'main'.
\--- com.google.guava:guava:33.3.1-jre
     +--- com.google.guava:failureaccess:1.0.2
     +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
     +--- com.google.code.findbugs:jsr305:3.0.2
     +--- org.checkerframework:checker-qual:3.43.0
     +--- com.google.errorprone:error_prone_annotations:2.28.0
     \--- com.google.j2objc:j2objc-annotations:3.0.0

testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- com.google.guava:guava:33.3.1-jre
|    +--- com.google.guava:failureaccess:1.0.2
|    +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|    +--- com.google.code.findbugs:jsr305:3.0.2
|    +--- org.checkerframework:checker-qual:3.43.0
|    +--- com.google.errorprone:error_prone_annotations:2.28.0
|    \--- com.google.j2objc:j2objc-annotations:3.0.0
+--- org.junit.jupiter:junit-jupiter:5.11.3
|    +--- org.junit:junit-bom:5.11.3
|    |    +--- org.junit.jupiter:junit-jupiter:5.11.3 (c)
|    |    +--- org.junit.jupiter:junit-jupiter-api:5.11.3 (c)
|    |    +--- org.junit.jupiter:junit-jupiter-engine:5.11.3 (c)
|    |    +--- org.junit.jupiter:junit-jupiter-params:5.11.3 (c)
|    |    +--- org.junit.platform:junit-platform-launcher:1.11.3 (c)
|    |    +--- org.junit.platform:junit-platform-commons:1.11.3 (c)
|    |    \--- org.junit.platform:junit-platform-engine:1.11.3 (c)
|    +--- org.junit.jupiter:junit-jupiter-api:5.11.3
|    |    +--- org.junit:junit-bom:5.11.3 (*)
|    |    +--- org.opentest4j:opentest4j:1.3.0
|    |    \--- org.junit.platform:junit-platform-commons:1.11.3
|    |         \--- org.junit:junit-bom:5.11.3 (*)
|    +--- org.junit.jupiter:junit-jupiter-params:5.11.3
|    |    +--- org.junit:junit-bom:5.11.3 (*)
|    |    \--- org.junit.jupiter:junit-jupiter-api:5.11.3 (*)
|    \--- org.junit.jupiter:junit-jupiter-engine:5.11.3
|         +--- org.junit:junit-bom:5.11.3 (*)
|         +--- org.junit.platform:junit-platform-engine:1.11.3
|         |    +--- org.junit:junit-bom:5.11.3 (*)
|         |    +--- org.opentest4j:opentest4j:1.3.0
|         |    \--- org.junit.platform:junit-platform-commons:1.11.3 (*)
|         \--- org.junit.jupiter:junit-jupiter-api:5.11.3 (*)
\--- org.junit.platform:junit-platform-launcher -> 1.11.3
     +--- org.junit:junit-bom:5.11.3 (*)
     \--- org.junit.platform:junit-platform-engine:1.11.3 (*)

输出清楚地显示 com.google.guava:guava:33.3.1-jre 依赖于 com.google.guava:failureaccess:1.0.2

步骤 5. 在 Build Scan® 中查看依赖

要在 Build Scan 中查看依赖项,请使用可选的 --scan 标志运行 build 任务。

tutorial 目录下,输入以下命令并按照提示接受条款

$ ./gradlew build --scan

BUILD SUCCESSFUL in 423ms
7 actionable tasks: 7 up-to-date

Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service. Do you accept these terms? [yes, no] yes

Gradle Terms of Service accepted.

Publishing build scan...
https://gradle.com/s/link

Build Scan 是一个可共享的、集中的构建记录,由 Gradle 提供免费服务。

点击提示中提供的链接:https://gradle.com/s/link

您必须接受服务条款才能使用 Build Scans。

您需要使用电子邮件激活 Build Scan

build scan prompt

您将在收件箱中收到扫描的最终链接,该链接应如下所示

build scan results

打开菜单中的Dependencies(依赖项)选项卡,展开 compileClasspathruntimeClasspathtestCompileClasspathtestRuntimeClasspath

build scan dependencies

正如预期,我们可以看到 Gradle 使用声明的依赖项 junitguava 来编译、运行和测试应用。

展开窗口中的 com.google.guava:guava:33.3.1-jreorg.junit.jupiter:junit-jupiter:5.11.3

build scan trans dependencies

junitguava 下面有几个传递性依赖。例如,com.google.code.findbugs:jsr305:3.0.2 传递性依赖来自 com.google.guava:guava:33.3.1-jre 依赖。

步骤 6. 更新项目依赖

添加和更改依赖项在 build 文件和版本目录中完成。

让我们更改 guava 版本,并看看这如何影响依赖树。

将版本目录中的 guava 依赖项更改为

gradle/libs.versions.toml
[versions]
guava = "30.0-jre"
junit-jupiter = "5.11.3"

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

如果您使用 IntelliJ 更改文件,请不要忘记点击 sync Gradle 按钮

intellij idea dep man

运行 ./gradlew build --scan 并查看 Build Scan 结果

build scan change

在终端中运行 ./gradlew :app:dependencies 查看依赖树中的更改

...

testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- com.google.guava:guava:30.0-jre
|    +--- com.google.guava:failureaccess:1.0.1
|    +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|    +--- com.google.code.findbugs:jsr305:3.0.2
|    +--- org.checkerframework:checker-qual:3.5.0
|    +--- com.google.errorprone:error_prone_annotations:2.3.4
|    \--- com.google.j2objc:j2objc-annotations:1.3
+--- org.junit.jupiter:junit-jupiter:5.11.3
|    +--- org.junit:junit-bom:5.11.3
|    |    +--- org.junit.jupiter:junit-jupiter:5.11.3 (c)
|    |    +--- org.junit.jupiter:junit-jupiter-api:5.11.3 (c)
|    |    +--- org.junit.jupiter:junit-jupiter-engine:5.11.3 (c)
|    |    +--- org.junit.jupiter:junit-jupiter-params:5.11.3 (c)
|    |    +--- org.junit.platform:junit-platform-launcher:1.11.3 (c)
|    |    +--- org.junit.platform:junit-platform-commons:1.11.3 (c)
|    |    \--- org.junit.platform:junit-platform-engine:1.11.3 (c)
|    +--- org.junit.jupiter:junit-jupiter-api:5.11.3
|    |    +--- org.junit:junit-bom:5.11.3 (*)
|    |    +--- org.opentest4j:opentest4j:1.3.0
|    |    \--- org.junit.platform:junit-platform-commons:1.11.3
|    |         \--- org.junit:junit-bom:5.11.3 (*)
|    +--- org.junit.jupiter:junit-jupiter-params:5.11.3
|    |    +--- org.junit:junit-bom:5.11.3 (*)
|    |    \--- org.junit.jupiter:junit-jupiter-api:5.11.3 (*)
|    \--- org.junit.jupiter:junit-jupiter-engine:5.11.3
|         +--- org.junit:junit-bom:5.11.3 (*)
|         +--- org.junit.platform:junit-platform-engine:1.11.3
|         |    +--- org.junit:junit-bom:5.11.3 (*)
|         |    +--- org.opentest4j:opentest4j:1.3.0
|         |    \--- org.junit.platform:junit-platform-commons:1.11.3 (*)
|         \--- org.junit.jupiter:junit-jupiter-api:5.11.3 (*)
\--- org.junit.platform:junit-platform-launcher -> 1.11.3
     +--- org.junit:junit-bom:5.11.3 (*)
     \--- org.junit.platform:junit-platform-engine:1.11.3 (*)

显然,guava 依赖项已更新到版本 30.0,并且传递性依赖项也发生了变化。

步骤 7. 运行 Java 应用

最后,使用 run 任务(无论是在终端还是 IDE 中)确保一切正常工作

./gradlew run

> Task :app:compileJava UP-TO-DATE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE

> Task :app:run
Hello World!

下一步: 应用插件 >>