读书笔记《gradle-effective-implementations-guide-second-edition》从Gradle开始
当我们开发软件时,我们编写、编译、测试、打包,最后分发代码。我们可以通过使用构建系统来自动化这些步骤。最大的优势是我们有一个可重复的步骤序列。构建系统将始终遵循我们定义的步骤,因此我们可以专注于编写实际代码,而不必担心其他步骤。
Gradle 就是这样一种构建系统。
在本章中,我们将介绍以下主题:
Gradle 入门
编写我们的第一个构建脚本
查看默认任务
了解命令行选项
讨论 Gradle 图形用户界面
Gradle 是一个构建自动化的工具。使用 Gradle,我们可以自动编译、测试、打包和部署我们的软件或任何其他类型的项目。 Gradle 很灵活,但对大多数项目都有合理的默认值。这意味着如果我们不想要一些特殊的东西,我们可以依赖默认值,但我们仍然可以使用灵活性来调整构建以适应某些自定义需求。
Gradle 已被 Spring、Hibernate 和 Grails 等大型开源项目使用。 LinkedIn 和 Netflix 等企业公司也使用 Gradle。
在本章中,我们将解释 Gradle 是什么以及如何在我们的开发项目中使用它。
让我们看一下 Gradle 的一些特性。
Gradle 使用基于 Groovy 的 Domain Specific Language (DSL)声明构建。 DSL 提供了一种灵活的语言,我们可以对其进行扩展。由于 DSL 基于 Groovy,我们可以编写 Groovy 代码来描述构建并使用 Groovy 语言的强大功能和表现力。 Groovy 是一种用于 Java 虚拟机 (JVM ),例如 Java 和 Scala。 Groovy 使使用集合变得容易,具有闭包和许多有用的特性。语法与Java 语法密切相关。事实上,我们可以用 Java 语法编写一个 Groovy 类文件,它会编译。然而,使用 Groovy 语法更容易表达代码意图,而且我们需要的样板代码比使用 Java 的要少。要充分利用 Gradle,最好同时学习 Groovy 语言的基础知识,但不必开始编写 Gradle 脚本。
Gradle 被设计成一种构建语言,而不是一个死板的框架。 Gradle 核心本身是用 Java 和 Groovy 编写的。要扩展 Gradle,我们可以使用 Java 和 Groovy 编写我们的自定义代码。如果我们愿意,我们甚至可以在 Scala 中编写我们的自定义代码。
Gradle 为 Java、Groovy、Scala、web 和 OSGi 项目提供开箱即用的支持。这些项目具有我们自己可能已经使用的合理的约定优于配置的设置。但是,如果我们的项目需要,我们可以灵活地更改这些配置设置。
Gradle 支持 Ant 任务 和项目。我们可以导入 Ant 构建并重用所有任务。但是,我们也可以编写依赖于 Ant Tasks 的 Gradle 任务。集成也适用于属性、路径等。
支持 Maven 和 Ivy 存储库发布或获取依赖项。因此,我们可以继续使用我们已经拥有的任何存储库基础设施。
使用 Gradle,我们可以进行增量构建。这意味着构建中的任务仅在必要时执行。例如,编译源代码的任务将首先检查自上次执行任务以来源代码是否发生了变化。如果源已更改,则执行任务;但如果源未更改,则跳过任务的执行并将任务标记为最新。
Gradle 为许多提供的任务支持这种机制。但是,我们也可以将它用于我们自己编写的任务。
Gradle 对多项目构建有很好的支持。一个项目可以简单地依赖于其他项目,也可以是其他项目的依赖项。我们可以定义项目之间的依赖关系图,Gradle 可以为我们解决这些依赖关系。我们可以根据需要灵活定义项目布局。
Gradle 支持部分构建。这意味着 Gradle 将确定我们的项目所依赖的项目是否需要重建。如果项目需要重新构建,Gradle 会在构建我们自己的项目之前执行此操作。
Gradle Wrapper 允许我们在计算机上未安装 Gradle 的情况下执行 Gradle 构建。这是分发源代码并为构建系统提供源代码以便构建源代码的好方法。
同样在企业环境中,我们可以为客户端计算机构建软件的零管理方式。我们可以使用包装器来强制使用某个 Gradle 版本,以便整个团队使用相同的版本。我们还可以更新包装器的 Gradle 版本,整个团队将使用更新的版本,因为包装器代码已签入到版本控制中。
在本节中,我们将在编写第一个 Gradle 构建脚本之前下载并安装 Gradle。
在我们安装 Gradle 之前,我们必须确保我们的计算机上安装了 Java Development SE Kit (JDK)。 Gradle 需要 JDK 6 或更高版本。 Gradle 将使用在我们计算机路径上找到的 JDK。我们可以通过在命令行上运行以下命令来检查这一点:
虽然 Gradle 使用了 Groovy,但我们不必自己安装 Groovy。 Gradle 将 Groovy 库与发行版捆绑在一起,并将忽略我们计算机上已经可用的 Groovy 安装。
Gradle 位于 Gradle 网站 http://www.gradle.org/downloads。从这个页面,我们可以下载最新版本的 Gradle。如果需要,我们也可以下载旧版本。我们可以在三种不同的发行版中进行选择下载。我们可以下载包含二进制文件、源代码和文档的完整 Gradle 发行版;或者我们只能下载二进制文件;或者我们只能下载源代码。
要开始使用 Gradle,我们将下载包含二进制文件、源代码和文档的标准发行版。在编写本书时,当前版本是 2.12。
Gradle 被打包为三个发行版之一的 ZIP 文件。因此,当我们下载了 Gradle 全发行版 ZIP 文件后,我们必须解压缩该文件。解压 ZIP 文件后,我们有:
bin
目录中的二进制文件doc
目录中包含用户指南、Groovy DSL 和 API 文档的文档samples
目录下有很多样例src
目录下Gradle的源码lib
目录下 Gradle 的支持库一个名为
init.d
的目录,我们可以在其中存放每次运行Gradle时需要执行的Gradle脚本
一旦我们将 Gradle 发行版解压到一个目录,我们就可以打开一个命令提示符。我们转到安装 Gradle 的目录。为了检查我们的安装,我们运行 gradle -v
并使用所使用的 JDK 和库版本的 Gradle 获得输出,如下所示:
在这里,我们可以检查显示的版本是否与我们从 Gradle 网站下载的分发版本相同。
要在我们的计算机上运行 Gradle,我们只需将 $GRADLE_HOME/bin
添加到我们的 PATH
环境变量中。完成此操作后,我们可以从计算机上的每个目录运行 gradle
命令。
如果我们想在 Gradle 中添加 JVM options,我们可以使用 JAVA_OPTS
和 ;GRADLE_OPTS
环境变量。 JAVA_OPTS
是一个常用的环境变量名称,用于将额外参数传递给 Java 应用程序。 Gradle 还使用 GRADLE_OPTS
环境变量将额外的参数传递给 Gradle。两个环境变量都被使用了,所以我们甚至可以用不同的值来设置它们。这主要用于设置,例如,HTTP 代理或额外的内存选项。
Software Development Kit Manager (SDKMAN!) 是一个工具管理软件开发工具包的版本,例如 Gradle。一旦我们安装了 SKDMAN!,我们就可以简单地使用 install
命令和 SDKMAN!下载 Gradle 并确保将其添加到我们的$PATH
变量中。软件开发者!可用于类 Unix 系统,例如 Linux、Mac OSX 和 Cygwin(在 Windows 上)。
首先,我们需要安装 SDKMAN! 在我们的 shell 中使用以下命令:
接下来,我们可以使用 install
命令安装 Gradle:
如果我们有多个版本的 Gradle,使用 use
命令很容易在版本之间切换:
我们现在有一个正在运行的 Gradle 安装。是时候创建我们的第一个 Gradle 构建脚本了。 Gradle 使用项目的概念来定义一组相关的任务。一个 Gradle 构建可以有一个或多个项目。项目在 Gradle 中是一个非常广泛的概念,但它主要是我们想要为我们的应用程序构建的一组组件。
一个项目有一个或多个任务。任务是需要由构建执行的工作单元。任务示例包括编译源代码、将类文件打包成 JAR 文件、运行测试和部署应用程序。
我们现在知道任务是项目的一部分,所以要创建我们的第一个任务,我们还要创建我们的第一个 Gradle 项目。我们使用 gradle
命令来运行构建。 Gradle 将在当前目录中查找名为 build.gradle
的文件。该文件是我们项目的构建脚本。我们定义了需要在这个构建脚本文件中执行的任务。
我们创建一个新的 build.gradle
文件并在文本编辑器中打开它。我们输入以下代码来定义我们的第一个 Gradle 任务:
使用此代码,我们将定义一个 helloWorld
任务。该任务会将单词 Hello world.
打印到控制台。 println
是一种 Groovy 将文本打印到控制台的方法,基本上是一种速记 System.out.println
Java 方法的版本。
括号之间的代码是 closure。闭包是可以分配给变量或传递给方法的代码块。 Java 不支持闭包,但 Groovy 支持。由于 Gradle 使用 Groovy 定义构建脚本,我们可以在构建脚本中使用闭包。
<<
语法从技术上讲是 leftShift()
方法的运算符简写,实际上意味着 添加到。因此,在这里我们定义我们想要将闭包(使用 println 'Hello world'
语句)添加到我们的任务中,使用 helloWorld
名称。
首先,我们保存 build.gradle
,并使用 gradle helloWorld
命令,执行我们的构建:
输出的第一行显示了我们的行 Hello world
。 Gradle 添加了更多输出,例如构建成功的事实和构建的总时间。由于 Gradle 在 JVM 中运行,每次我们运行 Gradle 构建时,也必须启动 JVM。输出的最后一行显示了一个提示,我们可以使用 Gradle 守护程序来运行我们的构建。稍后我们将讨论更多关于 Gradle 守护进程的信息,但它本质上是让 Gradle 在内存中运行,这样我们就不会因为每次运行 Gradle 时都启动 JVM 而受到惩罚。这大大加快了任务的执行速度。
我们可以再次运行相同的构建,但只能使用 Gradle --quiet
或 -q
输出我们的任务命令行选项。 Gradle 将抑制除错误消息之外的所有消息。当我们使用 --quiet
(或 -q
)选项时,我们得到以下输出:
我们可以通过一项任务创建简单的构建脚本。我们可以让 Gradle 向我们展示我们项目的可用任务。 Gradle 有几个我们可以执行的内置任务。我们输入 gradle -q
tasks 来查看我们项目的任务:
在这里,我们在Other tasks
部分看到了我们的helloWorld
任务。 Gradle 内置任务显示在 帮助任务
部分。例如,为了获取一些通用帮助信息,我们执行 help
任务:
properties
任务对于查看我们项目可用的属性非常有用。我们自己并没有在构建脚本中定义任何属性,但是 Gradle 提供了很多内置属性。以下输出显示了一些属性:
dependencies
任务将显示我们项目的依赖项(如果有的话)。我们的第一个项目没有任何依赖关系,正如我们运行任务时的输出所示:
projects
任务将显示根项目的子项目(如果有)。我们的项目没有任何子项目。因此,当我们运行 projects
任务时,输出显示我们的项目没有子项目:
model
任务显示有关 Gradle 从我们的项目构建文件内部构建的模型的信息。此功能正在孵化中,这意味着该功能在 Gradle 的未来版本中可能会发生变化:
我们将在本书中更多地讨论这些和其他任务。
在我们查看更多 Gradle 命令行选项之前,最好先讨论一下 Gradle 的实时保存功能:任务名称缩写。使用任务名称缩写,我们不必在命令行中输入完整的任务名称。我们只需输入足够多的名称以使其在构建中唯一。
在我们的第一个构建中,我们只有一个任务,所以 gradle h
命令应该可以正常工作。但是,我们没有考虑内置 help
任务。因此,为了唯一标识我们的 helloWorld
任务,我们使用 hello
缩写:
我们还可以缩写 CamelCase 任务名称中的每个单词。比如我们的helloWorld
任务名可以简写为 hW
:
此功能为我们节省了输入完整任务名称的时间,并且可以加快我们任务的执行速度。
通过一个简单的构建脚本,我们已经讨论了除了我们可以执行的我们自己的任务之外,我们还有几个默认任务。要执行多个任务,我们只需将每个任务名称添加到命令行。让我们执行我们的 helloWorld
自定义任务和内置 tasks
任务:
我们看到了这两个任务的输出。首先,执行helloWorld
,然后是 tasks
。在输出中,我们看到任务名称前面有一个冒号 (:
),输出在下一行。
Gradle 按照在命令行中定义的顺序执行任务。 Gradle 只会在构建期间执行一次任务。所以即使我们多次定义同一个任务,它也只会执行一次。当任务依赖于其他任务时,此规则也适用。 Gradle 将为我们优化任务执行,我们不必担心。
gradle
命令用于执行构建。此命令接受几个命令行选项。我们知道 --quiet
(或 -q
)选项可以减少构建的输出。如果我们使用 --help
(或 -h
或 -?< /code>) 选项,我们看到完整的选项列表,如下:
让我们更详细地看一些选项。 --quiet
(或 -q
), --debug
(或
-d
), --info
(或 - i
)、 --stacktrace
(或-s
)和 --full-stacktrace
(或-S
)选项控制我们在执行任务时看到的输出量。为了获得最详细的输出,我们使用 --debug
(或 -d
)选项。此选项提供大量输出,其中包含有关用于运行构建的步骤和类的信息。输出非常冗长,因此,我们不会使用太多。
为了更好地了解为我们的任务执行的步骤,我们可以使用 --info
(或 -i
) 选项。输出不像 --debug
那样冗长,但可以更好地理解构建步骤:
如果我们的构建抛出异常,我们可以使用 --stacktrace
(或 -s
)和 --full-stacktrace
(或 -S
)选项。后一个选项将输出最多的信息并且是最详细的。 --stacktrace
和 --full-stacktrace
选项可以与其他日志记录选项结合使用。
我们使用 build.gradle
名称创建了构建文件。这是构建文件的默认名称。 Gradle 将在当前目录中查找具有此名称的文件来执行构建。但是,我们可以使用 --build-file
(或 -b
)和 --project-dir
(或 -p
)命令行选项。
让我们从当前目录的父目录运行 gradle
命令:
我们也可以将我们的 build.gradle
重命名为,例如, hello.build
并且仍然执行我们的构建:
使用 --dry-run
(or -m
) 选项,我们可以运行所有任务而不真正执行它们。当我们使用 dry-run
选项时,我们可以看到正在执行的任务,因此我们可以深入了解特定构建场景中涉及的任务。我们甚至不必担心任务是否真正执行。 Gradle 构建了一个 有向无环图 (DAG)执行任何任务之前的所有任务。构建 DAG 以便任务将按照依赖关系的顺序执行,并且一个任务只执行一次:
我们已经讨论过 Gradle 在 JVM 中执行,每次调用 gradle
命令时,都会启动一个新的 JVM,加载 Gradle 类和库,然后执行构建.如果我们不必在每次执行构建时都加载 JVM 和 Gradle 类和库,我们可以减少构建执行时间。 --daemon
命令行选项启动一个新的 Java 进程,该进程将加载所有 Gradle 类和库,然后执行构建。下次当我们使用 --daemon
选项运行 Gradle 时,只会执行构建,因为具有所需 Gradle 类和库的 JVM 已经在运行。
我们第一次使用 --daemon
选项执行 Gradle 时,由于 Java 后台进程尚未启动,因此执行速度不会提高。但是,下一次,我们可以看到一个重大改进:
即使启动了守护进程,我们仍然可以在不使用守护进程的情况下运行 Gradle 任务。我们使用 --no-daemon
命令行选项来运行 Gradle 构建,然后不使用守护进程:
要停止守护进程,我们使用 --stop
命令行选项:
这将完全停止 Java 后台进程。
始终使用 --daemon
命令行选项,但我们不想每次运行时都键入它 gradle
命令,如果我们的操作系统支持别名,我们可以创建一个别名。例如,在基于 Unix 的系统上,我们可以创建一个别名,然后使用该别名来运行 Gradle 构建:
除了使用 --daemon
命令行选项,我们可以使用 org.gradle.daemon
Java 系统属性来启用守护程序。我们可以将此属性添加到 GRADLE_OPTS
环境变量中,以便在我们运行 Gradle 构建时始终使用它:
最后,我们可以在项目目录的根目录下添加一个 gradle.properties
文件。在该文件中,我们可以定义一个 org.gradle.daemon
属性并分配 true
值来启用 Gradle从此目录执行的所有构建的守护进程。
让我们创建一个 gradle.properties
文件,其内容如下:
我们可以运行我们的示例任务 helloWorld
,构建将使用 Gradle 守护进程:
Gradle 还提供了 --profile
命令行选项。此选项记录完成某些任务所需的时间。数据保存在 build/reports/profile
目录中的 HTML 文件中。我们可以在 Web 浏览器中打开这个文件并检查构建过程中几个阶段所花费的时间。下图显示了配置文件报告的 HTML 内容:
最后,我们看一下 --gui
命令行选项。使用这个选项,我们为我们的 Gradle 构建启动了一个图形 shell。到目前为止,我们使用命令行来启动任务。使用 Gradle GUI,我们可以对项目中的任务进行图形化概览,只需单击鼠标即可执行它们。
要启动 GUI,我们调用以下命令:
打开一个窗口,其中包含我们的任务树的图形概览。我们只有一个任务,它显示在任务树中,如下面的截图所示:
运行任务的输出显示在窗口底部。当我们第一次启动 GUI 时,tasks
任务被执行,我们在窗口中看到了输出。
任务树选项卡显示在我们的构建项目中找到的项目和任务。我们可以通过双击任务名称来执行任务。
默认情况下会显示所有任务,但我们可以应用过滤器来显示或隐藏某些项目和任务。 Edit filter 按钮打开一个新的对话框窗口,我们可以在其中定义属于过滤器的任务和属性。 切换过滤器按钮使过滤器处于活动或非活动状态。
我们也可以右键单击项目和任务名称。这将打开一个上下文菜单,我们可以在其中选择执行任务、将其添加到收藏夹、隐藏它(将其添加到过滤器中)或编辑构建文件。如果我们已将 .gradle
扩展名与我们操作系统中的文本编辑器相关联,则编辑器将使用构建脚本的内容打开。这些选项可以在以下屏幕截图中看到:
收藏夹选项卡存储我们要定期执行的任务。我们可以通过在 任务树选项卡中右键单击任务并选择 < strong>添加到收藏夹菜单选项,或者如果我们打开了 收藏夹选项卡,我们可以选择 添加按钮并手动输入我们要添加到收藏夹列表的项目和任务名称。我们可以在以下屏幕截图中看到 添加收藏夹对话框窗口:
最后一个选项卡是设置选项卡。在这里,我们可以更改项目目录,默认设置为当前目录。
我们在本章前面讨论了不同的日志记录级别作为命令行选项。使用 GUI,我们可以从 Log Level 选择框中选择不同日志级别的日志级别。我们可以选择 debug, 信息, 生命周期和 错误作为日志级别。错误日志级别只显示错误并且是最不详细的,而调试是最详细的日志级别。生命周期日志级别是默认日志级别。
在这里,我们还可以设置异常堆栈跟踪信息的详细程度。在 Stack Trace Output 部分,我们可以从以下三个选项中进行选择:
Exceptions Only:这是为了只在异常发生时显示异常,这是默认值
标准堆栈跟踪 (-s):用于显示更多异常堆栈跟踪信息
-S):这是针对异常的最详细的堆栈跟踪信息
如果我们启用 Only Show Output When Error Occurs 选项,那么我们只会在构建失败时从构建过程中获取输出。否则,我们不会得到任何输出。
最后,我们可以使用 Use Custom Gradle Executor 选项定义一种不同的方式来为构建启动 Gradle。例如,我们可以使用额外的设置信息定义不同的批处理或脚本文件来运行构建过程。以下屏幕截图显示了 设置标签页以及我们可以设置的所有选项: