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

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

讨论