Gradle-构建生命周期
两个重要的概念
项目
实际上,一个项目是什么取决于你要用 Gradle 做什么?项目通常代表的是构建内容。 例如在 Android 中,一个 module 就是一个项目;
- 项目是注册在 settings.gradle 中的
- 通常一个项目有一个 build.gradle
Gradle 构建就是由一个或多个项目组成的。
任务
任务 顾名思义就是一个在构建阶段被执行的操作。它是 Gradle 构建的原子工作单位。例如 编译 Java 源代码;
任务是定义在项目的构建脚本中,并且可以彼此依赖。
一个项目就是由一个个任务组成的。
每一个 Gradle 构建都会按照相同的顺序经历三个不同的阶段:
初始化
Gradle 支持单项目构建和多项目构建。
在这个阶段 Gradle 会确认哪些项目将会参与构建。Gradle 会通过 settings.gradle 确定是多项目还是单项目构建。
Gradle 会为每个项目创建 Project 实例。
配置
在这个阶段执行在初始化阶段中确定的每一个项目的配置脚本,但是并不会执行其中的任务,只会评估任务的依赖性,根据其依赖性创建任务的有向无环图。
Gradle引入了一个称为随需求变配置的特性,该特性使它能够在构建过程中只配置相关和必要的项目。这在大型多项目构建中非常有用,因为它可以大大减少构建时间。
执行
在这个阶段,Gradle 会识别在配置阶段创建的任务的有向无环图。并按照他们的依赖顺序开始执行。
所有的构建工作都是在这个阶段执行的。如编译源码,生成 .class 文件,复制文件等。
settings.gradle
这个文件是由 Gradle 约定命名的,默认名为 settings.gradle ,在初始化阶段被执行。
对于多项目构建,必须在这里声明要参与构建的所有项目。对于单项目构建就是可选的了,可有可无。
Gradle 是如何寻找 settings.gradle 的?
- 在当前目录寻找
- 没有找到的话就去父目录寻找
- 仍然没有找到就是是单项目构建了
- 如果找到了就是确定其中的项目,如果当前执行的项目在 settings.gradle 有定义就执行多项目构建,否则就执行单项目构建。
一个脚本的属性访问和方法调用是委托给 Project 类的实例的,类似的 settings.gradle 的属性访问和方法调用是委托给 Settings 类的实例对象的。
单项目构建
对于单项目构建,在初始化后的工作流程很简单,构建脚本针对初始化阶段创建的项目对象执行。查找在命令行传入的任务名称相同的任务。
如果任务存在则作为一个单独的构建按照命令行传递的顺序执行。
多项目构建
多项目构建是在 Gradle 的单个执行过程中构建多个项目的构建。必须把参与构建的项目声明在 settings.gradle 里
项目位置
可以把多项目构建看作一个单根的树。每一个项目都是树上的一个节点。一个项目有一个路径表示在树中的位置。
通常情况下项目的路径和在文件系统中的位置是一致的,当然了这个路径也是可以配置的。
项目树是 settings.gradle 生成的,默认情况下 settings.gradle 的位置就是根项目的位置。但是你可以在 settings.gradle 文件中更改。
构建项目树
在 settings.gradle 设置文件中你可以使用一些列的方法配置构建项目树。分层和平面物理布局都支持。
分层布局
Groovy
include 'project1', 'project2:child', 'project3:child1'
Kotlin
include("project1", "project2:child", "project3:child1")
include 方法使用项目路径作为参数,假定项目路径与相对物理文件系统路径相等。
例如 "project2:child" 默认对应的是相对于根目录的 "project2/child"。
这也意味着包含路径 “services:hotels:api” 将创建3个项目:
- “services”
- “services:hotels”
- “services:hotels:api”
更详细的说明可以 DSL文档
平面布局
Groovy
includeFlat 'project3', 'project4'
Kotlin
includeFlat("project3", "project4")
includeFlat 也是目录名字作为参数。这些目录要和根项目目录同级。
这些目录的位置在项目树中是根项目的子项目。
更改项目树的元素
在设置文件中创建的多项目树由所谓的项目描述符组成。这些项目符号可以随时更改。
可以通过下面这种方式访问描述符
查找项目树的元素
Groovy
println rootProject.name
println project(':projectA').name
Kotlin
println(rootProject.name)
println(project(":projectA").name)
使用这个描述符你可以一个项目的名字,项目目录和构建文件
更改项目树元素
Groovy
rootProject.name = 'main'
project(':projectA').projectDir = new File(settingsDir, '../my-project-a')
project(':projectA').buildFileName = 'projectA.gradle'
Kotlin
rootProject.name = "main"
project(":projectA").projectDir = File(settingsDir, "../my-project-a")
project(":projectA").buildFileName = "projectA.gradle"
更详细的信息可以查看 ProjectDescriptor 类的 API 文档。
接收生命周期事件
构建脚本可以接收生命周期构建进度的通知。
接收这些通知一般是两种形式
- 实现详细的监听接口
- 在发送通知时提供一个闭包来执行
项目评估事件
可以在项目评估后马上接到事件通知 使用的是 Project.afterEvaluate 方法,传入一个闭包,Gradle会将评估的项目和状态传递进闭包里。
Kotlin
afterEvaluate {
println("${project.getName()} 评估结果:${state.getExecuted()}")
}
Groovy
afterEvaluate{ project,state->
println "$project 评估成功否:${state.failure==null}"
}
如果是在多项目构建里,可以在 allprojects 的闭包里使用,这样每个项目的评估事件就都接受到了
Groovy
allprojects{
afterEvaluate{ project,state->
println "$project 评估成功否:${state.failure==null}"
}
}
评估前的事件通知使用 Project.beforeEvaluate 照样是传入一个闭包,Gradle会将要评估的项目传递进闭包里
Groovy
allprojects{
afterEvaluate{ project,state->
println "$project 评估成功否:${state.failure==null}"
}
beforeEvaluate { project ->
println "开始评估 $project"
}
}
这里列出了使用的 api文档。
任务
任务被添加到项目
Groovy
tasks.whenTaskAdded { task ->
println "$task 被添加到项目了。"
}
Kotlin
tasks.whenTaskAdded {
extra["srcDir"] = "src/main/java"
}
val a by tasks.registering
println("source dir is ${a.get().extra["srcDir"]}")
有向无环图填充完毕
使用的是 TaskExecutionGraph.whenReady 方法
Groovy
gradle.taskGraph.whenReady{ graph->
println "任务图准备好了:\n"
graph.allTasks.each {
print "$it , "
}
}
任务执行
Groovy
task ok
task broken(dependsOn: ok) {
doLast {
throw new RuntimeException('broken')
}
}
gradle.taskGraph.beforeTask { Task task ->
println "executing $task ..."
}
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (state.failure) {
println "FAILED"
}
else {
println "done"
}
}
这里留一个Gradle API 的查询地址
文档参考
- https://docs.gradle.org/current/userguide/build_lifecycle.html
- https://proandroiddev.com/understanding-gradle-the-build-lifecycle-5118c1da613f
Gradle-构建生命周期的更多相关文章
- Gradle 庖丁解牛(构建生命周期核心托付对象创建源代码浅析)
[工匠若水 http://blog.csdn.net/yanbober 未经同意严禁转载,请尊重作者劳动成果.私信联系我] 1 背景 上一篇<Gradle 庖丁解牛(构建源头源代码浅析)> ...
- 002-Apache Maven 构建生命周期
Maven - 构建生命周期 什么是构建生命周期 构建生命周期是一组阶段的序列(sequence of phases),每个阶段定义了目标被执行的顺序.这里的阶段是生命周期的一部分. 举例说明,一个典 ...
- Maven 使用了一个标准的目录结构和一个默认的构建生命周期。
Maven 使用了一个标准的目录结构和一个默认的构建生命周期. 约定优于配置 当创建 Maven 工程时,Maven 会创建默认的工程结构.开发者只需要合理的放置文件,而在 pom.xml 中不再需要 ...
- Maven 构建生命周期
构建生命周期是什么? 构建生命周期阶段的目标是执行顺序是一个良好定义的序列.这里使用一个例子,一个典型的 Maven 构建生命周期是由下列顺序的阶段: 阶段 处理 描述 准备资源 资源复制 资源复制可 ...
- Maven学习(十三)-----Maven 构建生命周期
Maven 构建生命周期 构建生命周期是什么? 构建生命周期阶段的目标是执行顺序是一个良好定义的序列. 这里使用一个例子,一个典型的 Maven 构建生命周期是由下列顺序的阶段: 阶段 处理 描述 准 ...
- Java-Maven-Runoob:Maven构建生命周期
ylbtech-Java-Maven-Runoob:Maven构建生命周期 1.返回顶部 1. Maven 构建生命周期 Maven 构建生命周期定义了一个项目构建跟发布的过程. 一个典型的 Mave ...
- Apache Maven(二):构建生命周期
Maven 约定的目录结构 我要遵循Maven已经约定好的目录结构,才能让maven在自动构建过程中找到对应的资源进行构建处理.以下是maven约定的目录结构: 项目名称 |-- pom.xml :M ...
- Maven的构建生命周期理解
以下引用官方的生命周期解释https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html: 一.构建生命 ...
- maven 学习---Maven构建生命周期
构建生命周期是一组阶段的序列(sequence of phases),每个阶段定义了目标被执行的顺序.这里的阶段是生命周期的一部分. 举例说明,一个典型的 Maven 构建生命周期是由以下几个阶段的序 ...
- Maven构建生命周期
以下引用官方的生命周期解释https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html: 一.构建生命 ...
随机推荐
- Ubuntu 18.04 root 使用ssh密钥远程登陆
前言: Ubuntu默认是禁止root用户远程登陆 本教程解决Ubuntu 18.04版本 root用户 使用ssh密钥无法远程登陆的问题 问题发生的环境: 腾讯云,重装Ubuntu服务器时选择使用s ...
- [记录]Shell并发模式批量安装saltstack的脚本
SaltStack+Shell: salt-master的配置: #cat /etc/salt/master user: root auto_accept: True salt-minion的配置(支 ...
- Spring Bean 的装配方式
Spring Bean 的装配方式 装配 Bean 的三种方式 一个程序中,许多功能模块都是由多个为了实现相同业务而相互协作的组件构成的.而代码之间的相互联系又势必会带来耦合.耦合是个具有两面性的概念 ...
- 洛谷 P1463、POI2002、HAOI2007 反素数
题意: 求最小的$x\in[1,N]$,使得$x$为$g(x)$最大的数 中最小的一个. 分析: 1.$x$不会有超过$10$个不同质因子.理由:$2 \times 3\times 5...\time ...
- Netty编码流程及WriteAndFlush()的实现
编码器的执行时机 首先, 我们想通过服务端,往客户端发送数据, 通常我们会调用ctx.writeAndFlush(数据)的方式, 入参位置的数据可能是基本数据类型,也可能对象 其次,编码器同样属于ha ...
- 7月新的开始 - LayUI的基本使用 - 分页
LayUI 分页处理 数据展示是以表格的形式展示的.使用模块如下: 首先使用内置模块-数据表格 然后使用内置模块-分页 官方文档地址:https://www.layui.com/doc/ 官方示例地址 ...
- springboot-权限控制shiro(一)
1. 场景描述 (1)权限控制是IT项目特别是企业项目,绕不开的重要模块,接下来结合springboot介绍下权限控制框架shiro. (2)springboot集成shiro的东西有点多,一篇博客完 ...
- 努力做一个优秀的programmer [ C# 影院售票系统]
Cinema.cs类 [Serializable] // 电影院类 public class Cinema { public Cinema() { //二进制 SoldTickets = new Li ...
- vue使用video.js解决m3u8视频播放格式
今天被这个关于m3u8视频播放不了搞了一下午,这个项目所有的视频流都是m3u8格式的,后台给我们返回的都是m3u8格式的视频流,解决了好长时间,看了好多博客,只有这个博客给我点启发,去解决这个问题,请 ...
- 【JDK】JDK源码分析-List, Iterator, ListIterator
List 是最常用的容器之一.之前提到过,分析源码时,优先分析接口的源码,因此这里先从 List 接口分析.List 方法列表如下: 由于上文「JDK源码分析-Collection」已对 Collec ...