认识 Gradle

[toc]

Gradle 是什么

Gradle 是一种开源构建自动化工具,其设计足够灵活,几乎可以构建任何类型的软件。以下是其一些最重要功能的高级概述:

高性能

Gradle 通过只运行需要运行的任务来避免不必要的工作,可由任务的输入发生变化而输出不同的结果。还可以使用构建缓存来重用来自先前运行或什至来自不同机器(具有共享构建缓存)的任务输出。

以 JVM 为磐石

Gradle 在 JVM 上运行,你必须安装 Java 开发工具包 (JDK) 才能使用它。这对于熟悉 Java 平台的用户来说是一个好处,因为你可以在构建逻辑中使用标准 Java API,例如自定义任务类型和插件。它还可以轻松地在不同平台上运行 Gradle。

请注意,Gradle 不仅限于构建 JVM 项目,它甚至还支持构建原生项目。

约定

Gradle 借鉴了 Maven 的书,并通过实现约定使常见类型的项目(例如 Java 项目)易于构建。

扩展性

你可以轻松扩展 Gradle 以提供你自己的任务类型甚至构建模型。

例如:它添加了许多新的构建概念,例如 flavors 和构建类型。

IDE 支持

几个主要的 IDE 允许你导入 Gradle 构建并与之交互:Android Studio、IntelliJ IDEA、Eclipse 和 NetBeans。Gradle 还支持生成将项目加载到 Visual Studio 所需的解决方案文件。

洞察

构建扫描提供有关构建运行的大量信息,你可以使用这些信息来识别构建问题。他们特别擅长帮助你识别构建性能的问题。你还可以与他人共享构建扫描,这在你需要寻求建议以解决构建问题时特别有用。

关于 Gradle 你需要知道的五件事

Gradle 是一个灵活而强大的构建工具,当你第一次开始时,很容易让人感到害怕。但是,了解以下核心原则将使 Gradle 更加平易近人,并且你将在不知不觉中熟练使用该工具。

1. Gradle 是一个通用的构建工具

Gradle 允许你构建任何软件,因为它对你尝试构建的内容或应该如何完成几乎没有任何假设。最显着的限制是依赖管理目前只支持 Maven 和 Ivy 兼容的存储库和文件系统。

这并不意味着你必须做很多工作才能创建构建。 Gradle 通过插件添加一层约定和预构建功能,可以轻松构建常见类型的项目(例如 Java 库)。你甚至可以创建和发布自定义插件来封装你自己的约定和构建功能。

2. 核心模型基于任务

Gradle 将其构建建模为任务(工作单元)的有向无环图 (DAG)。这意味着构建本质上是配置一组任务并将它们连接在一起——基于它们的依赖——以创建该 DAG。创建任务图后,Gradle 会确定哪些任务需要以何种顺序运行,然后继续执行它们。

该图显示了两个示例任务图,一个是抽象的,另一个是具体的,任务之间的依赖关系用箭头表示:

认识Gradle - 图1

几乎任何构建过程都可以通过这种方式建模为任务图,这也是 Gradle 如此灵活的原因之一。并且该任务图可以由插件和你自己的构建脚本定义,任务通过任务依赖机制链接在一起。

任务本身包括:

  • Actions - 做某事的工作,比如复制文件或编译源代码
  • Inputs - 操作使用或操作的值、文件和目录
  • Outputs - 操作修改或生成的文件和目录

事实上,根据任务需要做什么,上述所有内容都是可选的。某些任务(例如标准生命周期任务)甚至没有任何操作。为了方便起见,它们只是将多个任务聚合在一起。

你选择要运行的任务。通过指定执行你需要的任务来节省时间,但仅此而已。如果你只想运行单元测试,请选择执行此操作的任务 - 通常是 test 任务。如果你想打包一个应用程序,大多数构建都有一个 assemble 任务。

最后一件事:Gradle 支持的增量构建强大且可靠,因此除非你确实想要执行清理任务,否则通过避免 clean 任务来保持构建快速运行。

3. Gradle 有几个固定的构建阶段

了解 Gradle 分三个阶段评估和执行构建脚本很重要:

  1. Initialization
    为构建设置环境并确定哪些项目将参与其中。

  2. Configuration
    为 build 构建和配置任务图,然后根据用户想要运行的任务确定需要运行哪些任务以及以何种顺序运行。

  3. Execution
    运行在配置阶段结束时选择的任务。

这些阶段构成了 Gradle 的构建生命周期。

与 Apache Maven 术语的比较

Gradle 的构建阶段与 Maven 的阶段不同。 Maven 使用其阶段将构建执行划分为多个阶段。它们的作用与 Gradle 的任务图相似,但灵活性较差。

Maven 的构建生命周期概念与 Gradle 的生命周期任务大致相似。

精心设计的构建脚本主要由声明性配置而不是命令式逻辑组成。在配置阶段评估该配置是可以理解的。即便如此,许多此类构建也有任务操作——例如通过 doLast {} 和 doFirst {} 块——它们在执行阶段进行评估。这很重要,因为在配置阶段评估的代码不会看到在执行阶段发生的更改。

配置阶段的另一个重要方面是每次构建运行时都会评估其中涉及的所有内容。这就是为什么在配置阶段避免昂贵的工作是最佳实践的原因。构建扫描可以帮助你识别此类热点等

4. Gradle 的扩展方式不止一种

如果你可以仅使用与 Gradle 捆绑的构建逻辑来构建你的项目,那就太好了,但这几乎不可能。大多数构建都有一些特殊要求,这意味着你需要添加自定义构建逻辑。

Gradle 提供了几种允许您扩展它的机制,例如:

  • 自定义任务类型
    当您希望构建完成一些现有任务无法完成的工作时,您可以简单地编写自己的任务类型。通常最好将自定义任务类型的源文件放在 buildSrc 目录或打包插件中。然后,您可以像使用任何 Gradle 提供的任务类型一样使用自定义任务类型。

  • 自定义任务操作
    您可以通过 Task.doFirst() 和 Task.doLast() 方法附加在任务之前或之后执行的自定义构建逻辑。

  • 项目和任务的扩展属性
    这些允许您将自己的属性添加到项目或任务中,然后您可以从自己的自定义操作或任何其他构建逻辑中使用这些属性。额外的属性甚至可以应用于不是由您明确创建的任务,例如由 Gradle 的核心插件创建的任务。

  • 自定义约定
    约定是一种简化构建的有效方式,以便用户可以更轻松地理解和使用它们。这可以从使用标准项目结构和命名约定的构建中看出,例如 Java 构建。您可以编写自己的插件来提供约定——它们只需要为构建的相关方面配置默认值。

  • 自定义模型
    Gradle 允许您将新概念引入构建任务、文件和依赖项配置之外的构建中。您可以在大多数语言插件中看到这一点,它们将源集的概念添加到构建中。构建过程的适当建模可以大大提高构建的易用性和效率

5. 构建脚本针对 API 操作

将 Gradle 的构建脚本视为可执行代码很容易,因为它们就是这样。但这是一个实现细节:精心设计的构建脚本描述了构建软件所需的步骤,而不是这些步骤应该如何完成工作。这是自定义任务类型和插件的工作。

有一种常见的误解,认为 Gradle 的强大功能和灵活性来自它的构建脚本是代码这一事实。这与事实相去甚远。正是底层模型和 API 提供了强大的功能。正如我们在最佳实践中建议的那样,您应该避免在构建脚本中放置过多的命令式逻辑(如果有的话)。

然而,有一个领域可以将构建脚本视为可执行代码:理解构建脚本的语法如何映射到 Gradle 的 API。 API 文档(由 Groovy DSL 参考和 Javadocs 组成)列出了方法和属性,并引用了闭包和操作。这些在构建脚本的上下文中意味着什么?查看 Groovy Build Script Primer 以了解该问题的答案,以便您可以有效地使用 API 文档。

由于 Gradle 在 JVM 上运行,因此构建脚本也可以使用标准的 Java API。 Groovy 构建脚本可以额外使用 Groovy API,而 Kotlin 构建脚本可以使用 Kotlin API。