Gradle 如何工作 第一部分 - 启动
引言
这是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
的 JVM 的入口点是 org.gradle.launcher.GradleMain
类。
由 exec
启动的 JVM 是一个非常轻量级的 JVM。我们称之为 Gradle Client JVM
,因为它不运行任何实际的构建逻辑。它会查找兼容的 Gradle Daemon,如果找到则通过本地套接字连接到它。如果没有运行这样的守护进程,它将启动一个守护进程,它也是一个 JVM(Gradle Daemon JVM
)。稍后,
- 名为
Gradle Client JVM
的 JVM 将输入(命令行参数、环境变量、stdin 等)转发给Gradle Daemon JVM
。 - 名为
Gradle Daemon JVM
的 JVM 运行构建,并将输出(stdout/stderr)发送回Gradle Client JVM
。 - 构建完成后,
Gradle Client JVM
将退出,但Gradle Daemon JVM
可能会运行一段时间。
但是,此工作流有一个例外。如果您向 Gradle 构建传递 --no-daemon
,则客户端 JVM 可能会将自身转换为守护进程 JVM,前提是它与构建需求兼容。在这种情况下,没有守护进程,没有通信,也没有输入/输出转发——构建发生在单个 JVM 中。
但是,如果存在 --no-daemon
并且客户端 JVM 与构建需求不兼容,仍然会为构建启动一个新的可 disposable 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
的 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
内部发生的事情。