Gradle 工作原理 - 第 1 部分:启动
简介
这是Gradle 工作原理系列博客的第一篇,其中包括以下主题
- Gradle 如何启动
- Gradle 构建中涉及多少个 JVM
- 在构建期间,每个 JVM 中会发生什么
我们将在本博客中解释第一个主题Gradle 如何启动。在继续阅读之前,我们假设您熟悉基本的 JVM/Gradle 概念(jar、classpath、wrapper、daemon、project、task 等)。
Gradle 如何启动 #
启动 Gradle 构建有很多方法
- CLI 中的本地 Gradle 发行版:
/path/to/local/distribution/bin/gradle <SomeTask>
- CLI 中的 Gradle Wrapper:
./gradlew <SomeTask>
- 单击 IDE 中的按钮以导入 Gradle 项目或运行一些测试/任务
有什么区别?幕后发生了什么?在我们开始之前,我们需要记住 Gradle 是运行在 JVM 之上的软件(Java 虚拟机)。
CLI 中的本地 Gradle 发行版 #
您可能已手动或通过某些软件包管理工具将 Gradle 发行版下载到本地计算机。假设您通过键入 /path/to/local/distribution/bin/gradle <SomeTask>
启动 Gradle 构建。然后会发生什么?
在您最喜欢的文本编辑器中打开 /path/to/local/distribution/bin/gradle
,您会发现它没有什么神奇之处,只是一个纯文本文件,或者更准确地说,是一个 shell 脚本文件。当您说 /path/to/local/distribution/bin/gradle <SomeTask>
时,会启动一个 shell 进程并开始执行脚本中的代码。在此脚本的末尾,您可以看到一行
exec "$JAVACMD" "$@"
因此,脚本的工作很简单:它找到 java
命令,确定参数,并通过调用 exec
启动 JVM。exec
在同一进程中执行命令,即用 JVM 进程替换当前进程。
Gradle Client JVM
的入口点是 org.gradle.launcher.GradleMain
类。
由 exec
启动的 JVM 是一个非常轻量级的 JVM。让我们称之为 Gradle Client JVM
,因为它不运行任何真正的构建逻辑。它搜索兼容的 Gradle 守护进程,如果找到,则通过本地套接字连接到它。如果没有正在运行的守护进程,它将启动一个守护进程,这也是一个 JVM(Gradle Daemon JVM
)。稍后,
Gradle Client JVM
将输入(命令行参数、环境变量、stdin 等)转发到Gradle Daemon JVM
。Gradle Daemon JVM
运行构建,并将输出(stdout/stderr)发送回Gradle Client JVM
。- 构建完成后,
Gradle Client JVM
将退出,但Gradle Daemon JVM
可能会保持运行一段时间。
但是,此工作流程有一个例外。如果您将 --no-daemon
传递给 Gradle 构建,则如果客户端 JVM 与构建要求兼容,则客户端 JVM 可能会将自身转换为守护进程 JVM。在这种情况下,根本没有守护进程、没有通信、没有输入/输出转发 - 构建发生在单个 JVM 内部
但是,如果存在 --no-daemon
且客户端 JVM 与构建要求不兼容,则仍将为构建启动一个新的可一次性使用的 JVM,并在构建结束时退出
这就是本地 Gradle 发行版在 UNIX 操作系统上启动的方式。在 Windows 上,机制非常相似 - 唯一的区别是我们调用 /path/to/distribution/bin/gradle.bat
而不是 /path/to/distribution/bin/gradle
。
CLI 中的 Gradle Wrapper #
您可能知道,Gradle Wrapper 是执行 Gradle 构建的推荐方式。当您键入 ./gradlew <SomeTask>
时会发生什么?与从本地 Gradle 发行版运行有什么区别?
如果您在文本编辑器中打开 gradlew
,您会发现它与我们在上一节中解释的内容非常相似:没有魔法,只是一个 shell 脚本。它从项目中的 gradle/wrapper/gradle-wrapper.jar
启动一个微小的 JVM。此 JVM 将定位或下载在 gradle/wrapper/gradle-wrapper.properties
中声明的特定版本的 Gradle 发行版,然后它将通过 Java 反射在同一 JVM 内启动 Gradle。之后,这个微小的 JVM 充当上一节中解释的 Gradle Client JVM
。
Gradle Wrapper JVM
的入口点是 org.gradle.wrapper.GradleWrapperMain
类。
IDE 中的 Gradle #
在前面的章节中,Gradle Client JVM
是通过 CLI 启动的专用 JVM。实际上,它不必是专用的 JVM。Gradle 客户端可以是另一个 JVM 的一部分,即动态加载一些 Gradle jar 并充当“Gradle 客户端”的 JVM:搜索/连接到守护进程,启动新的守护进程,并与守护进程通信。这种编程 API 称为 Tooling API。
例如,当您在 IntelliJ IDEA 中单击 Gradle Sync
按钮时,IDEA 将启动一个特殊的 Gradle 构建,以通过 Tooling API 获取项目的必要信息(项目结构、依赖项、任务等)。 尽管如此,所有构建逻辑仍然发生在 Gradle Daemon JVM
中,而 Tooling API 只是读取构建结果并将其返回给调用者。
下一步是什么 #
在本系列的下一篇博客文章中,我们将解释 Gradle Daemon JVM
内部发生的事情。