Gradle
Gradle 介绍
Gradle 官方文档是这样介绍的 Gradle 的:
Gradle is an open-source build automationopen in new window tool flexible enough to build almost any type of software. Gradle makes few assumptions about what you’re trying to build or how to build it. This makes Gradle particularly flexible.
Gradle 是一个开源的构建自动化工具,它足够灵活,可以构建几乎任何类型的软件。Gradle 对你要构建什么或者如何构建它做了很少的假设。这使得 Gradle 特别灵活。
简单来说,Gradle 就是一个运行在 JVM 上的自动化的项目构建工具,用来帮助我们自动构建项目。
对于开发者来说,Gradle 的主要作用主要有 3 个:
- 项目构建:提供标准的、跨平台的自动化项目构建方式。
- 依赖管理:方便快捷的管理项目依赖的资源(jar 包),避免资源间的版本冲突问题。
- 统一开发结构:提供标准的、统一的项目结构。
Gradle 构建脚本是使用 Groovy 或 Kotlin 语言编写的,表达能力非常强,也足够灵活。
Gradle 是运行在 JVM 上的一个程序,它可以使用 Groovy 来编写构建脚本。
Groovy 是运行在 JVM 上的脚本语言,是基于 Java 扩展的动态语言,它的语法和 Java 非常的相似,可以使用 Java 的类库。Groovy 可以用于面向对象编程,也可以用作纯粹的脚本语言。在语言的设计上它吸纳了 Java、Python、Ruby 和 Smalltalk 语言的优秀特性,比如动态类型转换、闭包和元编程支持。
我们可以用学习 Java 的方式去学习 Groovy ,学习成本相对来说还是比较低的,即使开发过程中忘记 Groovy 语法,也可以用 Java 语法继续编码。
基于 JVM 的语言有很多种比如 Groovy,Kotlin,Java,Scala,他们最终都会编译生成 Java 字节码文件并在 JVM 上运行。
Gradle 优势
Gradle 是新一代的构建系统,具有高效和灵活等诸多优势,广泛用于 Java 开发。不仅 Android 将其作为官方构建系统, 越来越多的 Java 项目比如 Spring Boot 也慢慢迁移到 Gradle。
- 在灵活性上,Gradle 支持基于 Groovy 语言编写脚本,侧重于构建过程的灵活性,适合于构建复杂度较高的项目,可以完成非常复杂的构建。
- 在粒度性上,Gradle 构建的粒度细化到了每一个 task 之中。并且它所有的 Task 源码都是开源的,在我们掌握了这一整套打包流程后,我们就可以通过去修改它的 Task 去动态改变其执行流程。
- 在扩展性上,Gradle 支持插件机制,所以我们可以复用这些插件,就如同复用库一样简单方便。
Gradle Wrapper 介绍
Gradle 官方文档是这样介绍的 Gradle Wrapper 的:
The recommended way to execute any Gradle build is with the help of the Gradle Wrapper (in short just “Wrapper”). The Wrapper is a script that invokes a declared version of Gradle, downloading it beforehand if necessary. As a result, developers can get up and running with a Gradle project quickly without having to follow manual installation processes saving your company time and money.
执行 Gradle 构建的推荐方法是借助 Gradle Wrapper(简而言之就是“Wrapper”)。Wrapper 它是一个脚本,调用了已经声明的 Gradle 版本,如果需要的话,可以预先下载它。因此,开发人员可以快速启动并运行 Gradle 项目,而不必遵循手动安装过程,从而为公司节省时间和金钱。
我们可以称 Gradle Wrapper 为 Gradle 包装器,它将 Gradle 再次包装,让所有的 Gradle 构建方法在 Gradle 包装器的帮助下运行。
Gradle Wrapper 的工作流程图如下(图源Gradle Wrapper 官方文档介绍open in new window):
整个流程主要分为下面 3 步:
- 首先当我们刚创建的时候,如果指定的版本没有被下载,就先会去 Gradle 的服务器中下载对应版本的压缩包;
- 下载完成后需要先进行解压缩并且执行批处理文件;
- 后续项目每次构建都会重用这个解压过的 Gradle 版本。
Gradle Wrapper 会给我们带来下面这些好处:
- 在给定的 Gradle 版本上标准化项目,从而实现更可靠和健壮的构建。
- 可以让我们的电脑中不安装 Gradle 环境也可以运行 Gradle 项目。
- 为不同的用户和执行环境(例如 IDE 或持续集成服务器)提供新的 Gradle 版本就像更改 Wrapper 定义一样简单。
生成 Gradle Wrapper
如果想要生成 Gradle Wrapper 的话,需要本地配置好 Gradle 环境变量。Gradle 中已经内置了内置了 Wrapper Task,在项目根目录执行执行gradle wrapper
命令即可帮助我们生成 Gradle Wrapper。
执行命令 gradle wrapper
命令时可以指定一些参数来控制 wrapper 的生成。具体有如下两个配置参数:
--gradle-version
用于指定使用的 Gradle 的版本--gradle-distribution-url
用于指定下载 Gradle 版本的 URL,该值的规则是http://services.gradle.org/distributions/gradle-${gradleVersion}-bin.zip
执行gradle wrapper
命令之后,Gradle Wrapper 就生成完成了,项目根目录中生成如下文件:
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
每个文件的含义如下:
gradle-wrapper.jar
:包含了 Gradle 运行时的逻辑代码。gradle-wrapper.properties
:定义了 Gradle 的版本号和 Gradle 运行时的行为属性。gradlew
:Linux 平台下,用于执行 Gralde 命令的包装器脚本。gradlew.bat
:Windows 平台下,用于执行 Gralde 命令的包装器脚本。
gradle-wrapper.properties
文件的内容如下:
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionBase
:Gradle 解包后存储的父目录。distributionPath
:distributionBase
指定目录的子目录。distributionBase+distributionPath
就是 Gradle 解包后的存放的具体目录。distributionUrl
:Gradle 指定版本的压缩包下载地址。zipStoreBase
:Gradle 压缩包下载后存储父目录。zipStorePath
:zipStoreBase
指定目录的子目录。zipStoreBase+zipStorePath
就是 Gradle 压缩包的存放位置。
更新 Gradle Wrapper
更新 Gradle Wrapper 有 2 种方式:
- 接修改
distributionUrl
字段,然后执行 Gradle 命令。 - 执行 gradlew 命令
gradlew wrapper –-gradle-version [version]
。
下面的命令会将 Gradle 版本升级为 7.6。
gradlew wrapper --gradle-version 7.6
gradle-wrapper.properties
文件中的 distributionUrl
属性也发生了改变。
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
自定义 Gradle Wrapper
Gradle 已经内置了 Wrapper Task,因此构建 Gradle Wrapper 会生成 Gradle Wrapper 的属性文件,这个属性文件可以通过自定义 Wrapper Task 来设置。比如我们想要修改要下载的 Gralde 版本为 7.6,可以这么设置:
task wrapper(type: Wrapper) {gradleVersion = '7.6'
}
也可以设置 Gradle 发行版压缩包的下载地址和 Gradle 解包后的本地存储路径等配置。
task wrapper(type: Wrapper) {gradleVersion = '7.6'distributionUrl = '../../gradle-7.6-bin.zip'distributionPath=wrapper/dists
}
distributionUrl
属性可以设置为本地的项目目录,你也可以设置为网络地址。
Gradle 任务
在 Gradle 中,任务(Task)是构建执行的单个工作单元。
Gradle 的构建是基于 Task 进行的,当你运行项目的时候,实际就是在执行了一系列的 Task 比如编译 Java 源码的 Task、生成 jar 文件的 Task。
Task 声明方式如下(还有其他几种声明方式):
// 声明一个名字为 helloTask 的 Task
task helloTask{doLast{println "Hello"}
}
创建一个 Task 后,可以根据需要给 Task 添加不同的 Action,上面的“doLast”就是给队列尾增加一个 Action。
//在Action 队列头部添加ActionTask doFirst(Action<? super Task> action);Task doFirst(Closure action);//在Action 队列尾部添加ActionTask doLast(Action<? super Task> action);Task doLast(Closure action);//删除所有的ActionTask deleteAllActions();
一个 Task 中可以有多个 Acton,从队列头部开始向队列尾部执行 Acton。
Action 代表的是一个个函数、方法,每个 Task 都是一堆 Action 按序组成的执行图。
Task 声明依赖的关键字是dependsOn
,支持声明一个或多个依赖:
task first {doLast {println "+++++first+++++"}
}
task second {doLast {println "+++++second+++++"}
}// 指定多个 task 依赖
task print(dependsOn :[second,first]) {doLast {logger.quiet "指定多个task依赖"}
}// 指定一个 task 依赖
task third(dependsOn : print) {doLast {println '+++++third+++++'}
}
执行 Task 之前,会先执行它的依赖 Task。
我们还可以设置默认 Task,脚本中我们不调用默认 Task ,也会执行。
defaultTasks 'clean', 'run'task clean {doLast {println 'Default Cleaning!'}
}task run {doLast {println 'Default Running!'}
}
Gradle 本身也内置了很多 Task 比如 copy(复制文件)、delete(删除文件)。
task deleteFile(type: Delete) {delete "C:\\Users\\guide\\Desktop\\test"
}
Gradle 插件
Gradle 提供的是一套核心的构建机制,而 Gradle 插件则是运行在这套机制上的一些具体构建逻辑,其本质上和 .gradle
文件是相同。你可以将 Gradle 插件看作是封装了一系列 Task 并执行的工具。
Gradle 插件主要分为两类:
- 脚本插件:脚本插件就是一个普通的脚本文件,它可以被导入都其他构建脚本中。
- 二进制插件 / 对象插件:在一个单独的插件模块中定义,其他模块通过 Plugin ID 应用插件。因为这种方式发布和复用更加友好,我们一般接触到的 Gradle 插件都是指二进制插件的形式。
虽然 Gradle 插件与 .gradle 文件本质上没有区别,.gradle
文件也能实现 Gradle 插件类似的功能。但是,Gradle 插件使用了独立模块封装构建逻辑,无论是从开发开始使用来看,Gradle 插件的整体体验都更友好。
- 逻辑复用: 将相同的逻辑提供给多个相似项目复用,减少重复维护类似逻辑开销。当然 .gradle 文件也能做到逻辑复用,但 Gradle 插件的封装性更好;
- 组件发布: 可以将插件发布到 Maven 仓库进行管理,其他项目可以使用插件 ID 依赖。当然 .gradle 文件也可以放到一个远程路径被其他项目引用;
- 构建配置: Gradle 插件可以声明插件扩展来暴露可配置的属性,提供定制化能力。当然 .gradle 文件也可以做到,但实现会麻烦些。
Gradle 构建生命周期
Gradle 构建的生命周期有三个阶段:初始化阶段,配置阶段和运行阶段。
在初始化阶段与配置阶段之间、配置阶段结束之后、执行阶段结束之后,我们都可以加一些定制化的 Hook。
初始化阶段
Gradle 支持单项目和多项目构建。在初始化阶段,Gradle 确定哪些项目将参与构建,并为每个项目创建一个 Project 实例open in new window 。本质上也就是执行 settings.gradle
脚本,从而读取整个项目中有多少个 Project 实例。
配置阶段
在配置阶段,Gradle 会解析每个工程的 build.gradle
文件,创建要执行的任务子集和确定各种任务之间的关系,以供执行阶段按照顺序执行,并对任务的做一些初始化配置。
每个 build.gradle
对应一个 Project 对象,配置阶段执行的代码包括 build.gradle
中的各种语句、闭包以及 Task 中的配置语句。
在配置阶段结束后,Gradle 会根据 Task 的依赖关系会创建一个 有向无环图 。
运行阶段
在运行阶段,Gradle 根据配置阶段创建和配置的要执行的任务子集,执行任务。