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

  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。在这种情况下,根本没有守护进程、没有通信、没有输入/输出转发 - 构建发生在单个 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 内部发生的事情。

讨论