两个重要的概念

项目

实际上,一个项目是什么取决于你要用 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 的?

  1. 在当前目录寻找
  2. 没有找到的话就去父目录寻找
  3. 仍然没有找到就是是单项目构建了
  4. 如果找到了就是确定其中的项目,如果当前执行的项目在 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 的查询地址

文档参考

Gradle-构建生命周期的更多相关文章

  1. Gradle 庖丁解牛(构建生命周期核心托付对象创建源代码浅析)

    [工匠若水 http://blog.csdn.net/yanbober 未经同意严禁转载,请尊重作者劳动成果.私信联系我] 1 背景 上一篇<Gradle 庖丁解牛(构建源头源代码浅析)> ...

  2. 002-Apache Maven 构建生命周期

    Maven - 构建生命周期 什么是构建生命周期 构建生命周期是一组阶段的序列(sequence of phases),每个阶段定义了目标被执行的顺序.这里的阶段是生命周期的一部分. 举例说明,一个典 ...

  3. Maven 使用了一个标准的目录结构和一个默认的构建生命周期。

    Maven 使用了一个标准的目录结构和一个默认的构建生命周期. 约定优于配置 当创建 Maven 工程时,Maven 会创建默认的工程结构.开发者只需要合理的放置文件,而在 pom.xml 中不再需要 ...

  4. Maven 构建生命周期

    构建生命周期是什么? 构建生命周期阶段的目标是执行顺序是一个良好定义的序列.这里使用一个例子,一个典型的 Maven 构建生命周期是由下列顺序的阶段: 阶段 处理 描述 准备资源 资源复制 资源复制可 ...

  5. Maven学习(十三)-----Maven 构建生命周期

    Maven 构建生命周期 构建生命周期是什么? 构建生命周期阶段的目标是执行顺序是一个良好定义的序列. 这里使用一个例子,一个典型的 Maven 构建生命周期是由下列顺序的阶段: 阶段 处理 描述 准 ...

  6. Java-Maven-Runoob:Maven构建生命周期

    ylbtech-Java-Maven-Runoob:Maven构建生命周期 1.返回顶部 1. Maven 构建生命周期 Maven 构建生命周期定义了一个项目构建跟发布的过程. 一个典型的 Mave ...

  7. Apache Maven(二):构建生命周期

    Maven 约定的目录结构 我要遵循Maven已经约定好的目录结构,才能让maven在自动构建过程中找到对应的资源进行构建处理.以下是maven约定的目录结构: 项目名称 |-- pom.xml :M ...

  8. Maven的构建生命周期理解

    以下引用官方的生命周期解释https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html: 一.构建生命 ...

  9. maven 学习---Maven构建生命周期

    构建生命周期是一组阶段的序列(sequence of phases),每个阶段定义了目标被执行的顺序.这里的阶段是生命周期的一部分. 举例说明,一个典型的 Maven 构建生命周期是由以下几个阶段的序 ...

  10. Maven构建生命周期

    以下引用官方的生命周期解释https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html: 一.构建生命 ...

随机推荐

  1. ItemsControl绑定的数据模板显示不同样式:模板选择器

    总所周知,wpf提供了数据模板,列表控件可以绑定数据实现批量显示同类型数据.不过同个数据模板显示不同的样式怎么办?这时我们可以用模板选择器. 首先我们可以将数据绑定到首先定义资源样式 <Data ...

  2. python基础知识四 小数据池,深浅拷贝,集合+菜中菜

    四.小数据池,深浅拷贝,集合+菜中菜 1小数据池 --缓存机制(驻留机制) ​ '==' 判断两边内容是否相等 ​ 'is' 基于内存地址进行判断是否相同 a = 10 b = 10 print(a ...

  3. 1.svn 彻底clear时,注意代码备份 2.借助vc助手加头文件

    1.svn 彻底clear时,注意代码备份 2.不小心彻底clear可以在回收站找到 3.借助vc助手加头文件

  4. vector是序列式容器而set是关联式容器。set包含0个或多个不重复不排序的元素。

    1.vector是序列式容器而set是关联式容器.set包含0个或多个不重复不排序的元素.也就是说set能够保证它里面所有的元素都是不重复的.另外对set容器进行插入时可以指定插入位置或者不指定插入位 ...

  5. drop、truncate和delete的区别 [转载]

    drop.truncate和delete的区别 本文转载自: https://www.cnblogs.com/zhizhao/p/7825469.html     (1)DELETE语句执行删除的过程 ...

  6. C++ 过滤出字符串的中文(GBK,UTF-8)

    最近在处理游戏敏感词之类的东西,为了加强屏蔽处理,所以需要过滤掉字符串中的除汉字之外的是其他东西如数字,符号,英文字母等. 首先我查阅资料并写了个函数: 示例:返回输入字符串中汉字的个数: std:: ...

  7. 温故而知新,重温 Java 7 的那些“新”特性

    2009 年 4 月 20 日,Java 的亲生父亲 Sun 被养父 Oracle 以 74 亿美元收购,这在当时可是一件天大的事.有不少同学都担心 Java 的前途,我当时傻不啦叽地也很担心:自己刚 ...

  8. On The Way—Step 2 Python入门之Python内容初始

    2.1 输出 print() ​ 打印一个字符串 print('你真好!') ​ 打印变量内容 a = '你真好!' print(a) 结果都是:你真好! 2.2 变量 变量名字规则 只能用下划线.字 ...

  9. 解决axios接收二进制流文件乱码问题

    1. 须将axios 配置中的responseType设置为'arraybuffer',这样就不会让表格出现乱码现象: 2. 如果要动态设置文件名则需要让后台将名字设置到响应头中,否则将是一个乱码的文 ...

  10. Kafka服务不可用(宕机)问题踩坑记

    背景 某线上日志收集服务报警,打开域名报502错误码. 收集服务由2台netty HA服务器组成,netty服务器将客户端投递来的protobuf日志解析并发送到kafka,打开其中一个应用的日志,发 ...