Gradle 工作原理 第一部分 - 启动
这是 Gradle 工作原理 系列博客的第一篇,涵盖以下主题
- Gradle 如何启动
- Gradle 构建中涉及多少个 JVM
- 构建过程中每个 JVM 中发生了什么
本博客将解释第一个主题 Gradle 如何启动。在继续阅读之前,我们假设您熟悉基本的 JVM/Gradle 概念(jar、classpath、wrapper、daemon、project、task 等)。
Gradle 如何启动
有多种方法可以启动 Gradle 构建
- 本地 Gradle 分发版在 CLI 中:
/path/to/local/distribution/bin/gradle <SomeTask>
- Gradle Wrapper 在 CLI 中:
./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 Daemon,如果找到,则通过本地套接字连接到它。如果没有这样的守护进程运行,它将启动一个守护进程,它也是一个 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 内。
但是,如果存在 --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 被称为 工具 API。
例如,当您在 IntelliJ IDEA 中点击 Gradle Sync
按钮时,IDEA 将启动一个特殊的 Gradle 构建,通过工具 API 获取项目所需的信息(项目结构、依赖项、任务等)。不过,所有的构建逻辑都在 Gradle Daemon JVM
中进行,工具 API 只是读取构建结果并将其返回给调用者。
下一步
在 本系列的下一篇文章 中,我们将解释 Gradle Daemon JVM
内部发生了什么。