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)。之后,

  1. Gradle Client JVM 将输入(命令行参数、环境变量、stdin 等)转发到 Gradle Daemon JVM
  2. Gradle Daemon JVM 运行构建,并将输出(stdout/stderr)发送回 Gradle Client JVM
  3. 构建完成后,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 内部发生了什么。

讨论