01. Gradle-理解构建声明周期.md

我们之前说过,Gradle 的核心是一种基于依赖关系的编程语言。在 Gradle,这意味着您可以定义任务和任务之间的依赖关系。Gradle 保证这些任务按照其依赖项的顺序执行,并且每个任务只执行一次。这些任务形成了一个有向无环图。有些构建工具在执行任务时构建这样的依赖关系图。在任何任务执行之前,Gradle 构建完整的依赖关系图。这是 Gradle 的心脏地带,使许多在其他地方不可能实现的事情成为可能。

构建脚本配置这个依赖关系图。因此,严格来说,它们是构建配置脚本。

Build phases 构建阶段

一个 Gradle 构建有三个不同的阶段。

  • Initialization 初始化 Gradle 支持单个和多个项目的构建。在初始化阶段,Gradle 确定哪些项目将参与构建,并为每个项目创建一个 Project 实例。
  • Configuration 配置 在此阶段配置项目对象。执行构建的所有项目的构建脚本。
  • Execution 执行 Gradle 确定要执行的任务的子集,这些任务是在配置阶段创建和配置的。子集由传递给 gradle 命令和工作目录的任务名参数决定。然后,Gradle 执行所选择的每个任务。

Settings file 设置文件

在构建脚本文件旁边,Gradle 定义了一个设置文件。 设置文件由 Gradle 通过一个变数命名原则文件夹确定。 这个文件的默认名称是 settings.gradle。 在本章的后面,我们将解释 Gradle 如何查找设置文件。

设置文件在初始化阶段执行。 多项目构建必须在多项目层次结构的根项目中有 settings.gradle 文件。 这是必需的,因为设置文件定义了哪些项目正在参与多项目构建(参见创作多项目构建)。 对于单项目生成,设置文件是可选的。

除了定义所包含的项目之外,您可能还需要它将库添加到构建脚本类路径中(请参见 organizinggradle 项目)。 让我们首先用一个单独的项目构建做一些反思:

settings.gradle.kts

1
2
rootProject.name = "basic"
println("This is executed during the initialization phase.")

build.gradle.kts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
println("This is executed during the configuration phase.")

tasks.register("configured") {
println("This is also executed during the configuration phase, because :configured is used in the build.")
}

tasks.register("test") {
doLast {
println("This is executed during the execution phase.")
}
}

tasks.register("testBoth") {
doFirst {
println("This is executed first during the execution phase.")
}
doLast {
println("This is executed last during the execution phase.")
}
println("This is executed during the configuration phase as well, because :testBoth is used in the build.")
}

执行命令 gradle test testBoth

输出结果为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> gradle test testBoth
This is executed during the initialization phase.

> Configure project :
This is executed during the configuration phase.
This is executed during the configuration phase as well, because :testBoth is used in the build.

> Task :test
This is executed during the execution phase.

> Task :testBoth
This is executed first during the execution phase.
This is executed last during the execution phase.

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

对于生成脚本,属性访问和方法调用被委托给项目对象。 类似地,设置文件中的属性访问和方法调用也被委派给设置对象。 有关更多信息,请查看 API 文档中的 Settings 类。

初始化

Gradle 如何知道是否进行单个项目构建或多个项目构建?如果您从一个包含 setings.Gradle 文件的目录触发一个多项目构建,Gradle 将使用它来配置构建。Gradle 还允许您在参与构建的任何子项目中执行构建。[1]如果你在一个没有 setings.Gradle 文件的项目中执行 Gradle,Gradle 会通过以下方式查找 setings.Gradle 文件:

它在父目录中查找 setings.gradle。

如果未找到,则将生成作为单个项目生成执行。

如果找到 setings.Gradle 文件,Gradle 将检查当前项目是否属于在已找到的 setings.Gradle 文件中定义的多项目层次结构的一部分。否则,生成将作为单个项目生成执行。否则将执行多项目构建。

这种行为的目的是什么?Gradle 需要确定您所在的项目是否是多项目构建的子项目。当然,如果它是一个子项目,那么只构建子项目及其依赖项目,但是 Gradle 需要为整个多项目构建创建构建配置(参见 Configuration and Execution)。如果当前项目包含 setings.gradle 文件,则构建始终按以下方式执行:

如果 setings.gradle 文件没有定义多项目层次结构,那么只需要一个项目构建

一个多项目构建,如果 setings.gradle 文件确实定义了多项目层次结构。

自动搜索 setings.gradle 文件只适用于具有默认项目布局的多项目构建,其中项目路径与磁盘上的物理子项目布局匹配。Gradle 支持多项目构建的任意物理布局,但是对于这种任意布局,您需要从设置文件所在的目录执行构建。有关如何从根运行部分生成的信息,请参见根据任务的完全限定名执行任务。

Gradle 为参与构建的每个项目创建一个 Project 对象。对于多项目生成,这些是在 Settings 对象(加上根项目)中指定的项目。默认情况下,每个项目对象的名称等于其顶级目录的名称,除根项目外,每个项目都有一个父项目。任何项目都可能有子项目。

单个项目生成的配置和执行

对于单个项目构建,初始化后阶段的工作流非常简单。生成脚本针对在初始化阶段创建的项目对象执行。然后,Gradle 查找名称与作为命令行参数传递的任务相等的任务。如果存在这些任务名称,它们将按照传递它们的顺序作为单独的构建执行。配置和执行中讨论了多项目构建的配置和执行。

响应构建脚本中的生命周期

构建脚本可以随着构建在其生命周期中的进展而接收通知。这些通知通常采取两种形式: 您可以实现特定的侦听器接口,或者您可以提供一个闭包,以便在触发通知时执行。有关如何使用侦听器接口的详细信息,请参阅 API 文档。

参考

Build Lifecycle
https://docs.gradle.org/7.6/userguide/build_lifecycle.html#build_lifecycle_events