第三天:Gradle 的 5 个重要观念

Gradle 可以做的事情实在太多了,导致初学者很容易被其强大又神秘的架构吓到。因此笔者觉得有必要把官方文件上的这一段翻译并整理出来,让大家在学习 Gradle 前有正确的认知架构。

一、Gradle 是一个通用的建置工具

Gradle 可以帮我们建置几乎任何软件,因为它对我们的专案内容及要如何完成几乎没有任何限制。唯一的限制就是目前相依管理只支援 Maven 及 Ivy 兼容的程序码储存库和档案系统。

这样听起来好像我们会需要做很多前置才能建立建置工作?其实不会!

Gradle 可以透过外挂将常用的惯例作法或预建构功能载入,让建置常见类型的专案(例如 Java/Kotlin 函式库)变得容易。我们甚至可以建立和发布客制化外挂来封装特定惯例和建置功能。

二、整个核心是建构在任务(Task)之上

Gradle 的运作核心由一连串的任务(工作单元)所组成,也就是说当要进行建置时,Gradle 会将所有要进行的任务依照它们的相依性连结在一起成为 Directed Acyclic Graphs (DAGs)。当任务图建立後,Gradle 会确定哪些任务需要以何种顺序运行,然後执行它们。

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

几乎任何建置都可以用这种方式绘制出任务图,这也是 Gradle 很灵活的原因。任务图可以由外挂和客制化的建置脚本定义,任务通过任务相依机制连接在一起。一个任务包括:

  • 操作(Actions):执行某个工作,比方说复制档案或编译原始码。
  • 输入(Inputs):被拿来操作的值、档案或资料夹。
  • 输出(Outputs):被修改或产生出来的档案或资料夹。

事实上,根据任务的内容,上述所有元素都是选择性的,比方说标准的生命周期任务甚至没有任何操作。有时将这些任务组合在一起只是为了方便。

值得一提的是,Gradle 的累加组建(Incremental Build)是坚固且可靠的,因此除非你确实想要执行清理任务,否则不需执行清理任务,如此可以确保建置的运行速度。

三、Gradle 的 3 个固定建置阶段

Gradle 有 3 个评估和执行建置脚本阶段,这些阶段组成了一个 Gradle 的建置生命周期:

  1. 初始化:为建置任务设置环境并确定哪些专案将参与其中。
  2. 设定:为建置工作建构和设定任务图,依据使用者想执行的任务来决定哪些任务需要以何种顺序执行。
  3. 执行:执行在设定阶段结束时选择的任务。

良好设计的建置脚本是由声明式设定而不是命令式逻辑组成。在设定阶段评估该设定是可以理解的,即便如此,许多此类建置也有任务操作,例如透过 doLast {}doFirst {} 在执行阶段进行评估。这点很重要,因为在配定阶段评估的程序码不会看到在执行阶段发生的更改。

设定阶段的另一个重点是每次建置运行时都会评估其中涉及的所有内容,这就是为什麽在设定阶段的最佳实践是要避开昂贵的工作。建置扫描(Build Scan)可以帮助您识别此类 Hotspot 等。

四、Gradle 支援不止一种扩充方式

假如可以只用 Gradle 内建的建置指令来建置专案就太好了!可惜大多数的专案都有一些特殊需求需要另外写一些客制化的建置逻辑。Gradle 提供 5 种扩充机制,包括:

  1. 客制化任务类型:当你希望建置完成一些现有任务无法完成的工作时,你可以简单地编写自己的任务类型。一般来说,最好将客制化任务类型的原始码放在 buildSrc 资料夹或封装成外挂。然後,你可以像使用任何 Gradle 提供的任务类型一样使用客制化任务类型。

  2. 客制化任务操作:你可以透过 Task.doFirst()Task.doLast() 方法附加在任务之前或之後执行的客制化建置逻辑。

  3. 专案和任务的额外属性:Gradle 允许你将自己的属性增加到专案或任务中,然後你可以从自己的客制化操作或任何其他建置逻辑中使用这些属性。额外的属性甚至可以应用於不是由你显式建立的任务,例如由 Gradle 的核心外挂建立的任务。

  4. 客制化惯例:惯例是一种简化建置的有效方式,这让使用者可以更轻松地理解和使用它们。这可以从使用标准专案结构和命名约定的建置中看出,例如 Java/Kotlin 建置。我们可以编写自己的外挂来提供惯例,它们只需要为建置相关方面设定预设值。

  5. 客制化 Model:Gradle 允许我们将新概念引入建置任务、档案和相依设定。你可以在许多语言外挂中看到这一点,它们将 Source Set 的概念加到建置中。建置过程的适当建模可以大大提高建置的易用性和效率。

五、建置脚本依照 API 运作

把 Gradle 的建置脚本视为可执行的程序码很容易,因为它们的确就是这样。但这里有一个实作细节:精心设计的建置脚本描述了建置软件所需的步骤,而不是这些步骤应该如何完成工作。这是客制化任务类型和外挂的工作。

然而,有一个领域可以将建置脚本视为可执行的程序码:理解建置脚本的语法如何映射到 Gradle 的 API。 API 文件是由 Groovy DSL 和 Javadocs 组成,其列出了方法和属性,并引用了 Closure 和操作。这些在建置脚本的脉络中代表着什麽?你可以查询 Groovy Build Script Primer 以了解这个问题的答案,如何就能有效地使用 API 文件。

参考资料


<<:  爱用iPhone的UI/UX设计师最恐怖

>>:  [Day 3] Leetcode 848. Shifting Letters (C++)

机器学习:Feature Engineering 课程学习总结

总结:通过对features进行归类和操作,让features更加符合traindata的需求; 1...

[Day30] 第三十 - 总结技能交换系统(整合Laravel以及Express的Microservices)

前言(心得) 昨天在写Code的时候一不注意时间就超过了 其实我本来是很懒惰容易放弃的人 在之前的参...

[前端暴龙机,Vue2.x 进化 Vue3 ] Day11.列表渲染

当我们有很多重复的架构,内容却不一样,以旧有无框架的开发,我们可能就需要手动一笔一笔的刻出来,更进步...

Day 28 - styled-components 笔记3

Q_Q .. 对预设建立的 component 延伸自订样式 import styled from...

[Lesson10] Machine Learning

今天要来试着使用Firebase的机器学习套件,点击左边的Machine Learning 可以看到...