当前位置: 首页 > news >正文

Gradle Task的理解和实战使用

文章目录

    • 1 项目的生命周期
    • 2 Settings文件
    • 3 Task任务
      • 3.1 任务的行为
      • 3.2 任务依赖方式
        • 3.2.1 参数方式依赖
        • 3.2.2 内部依赖
        • 3.2.3 外部依赖
        • 3.2.4 跨项目依赖
      • 3.3 执行任务的命令与参数
      • 3.4 任务定义方式
        • 3.4.1 task方法
        • 3.4.2 create和register 方法
      • 3.5 任务类型
        • 3.5.1 常见任务类型
        • 3.5.2 自定义Task类型
      • 3.6 任务执行顺序
      • 3.7 动态分配任务
      • 3.8 任务的关闭与开启
      • 3.9 任务的超时
      • 3.10 任务的查找
      • 3.11 任务的规则
      • 3.12 任务的onlyIf断言
      • 3.13 默认的任务

1 项目的生命周期

Gradle 项目的生命周期分为三大阶段: Initialization -> Configuration -> Execution. 每个阶段都有自己的职责,具体如下图所示:

在这里插入图片描述

Initialization 阶段:主要目的是初始化构建, 它又分为两个子过程,一个是执行 Init Script,另一个是执行 Setting Script。

Init Script即init.gradle 文件会在每个项目 build 之前被调用,用于做一些初始化的操作,它主要有如下作用:

  • 配置内部的仓库信息(如公司的 maven 仓库信息);
  • 配置一些全局属性;
  • 配置用户名及密码信息(如公司仓库的用户名和密码信息)。

Setting Script 即settings.gradle 则更重要, 它初始化了一次构建所参与的所有模块。

Configuration 阶段:这个阶段开始加载项目中所有模块的 Build Script。所谓 “加载” 就是执行 build.gradle 中的语句, 根据脚本代码创建对应的 task, 最终根据所有 task 生成由 Task 组成的有向无环图(Directed Acyclic Graphs),如下:

在这里插入图片描述
从而构成如下有向无环树:
在这里插入图片描述

Execution 阶段:这个阶段会根据上个阶段构建好的有向无环图,按着顺序执行 Task【Action 动作】。

2 Settings文件

settings文件即为settings.gradle,不能改变其名字,必须放在根工程目录下。settings.gradle文件的作用主要是在项目初始化阶段确定一下引入哪些工程需要加入到项目构建中,即构建项目工程树(这里gradle的项目工程树的概念类似于 maven 中的 project 与 module)做准备。

项目工程树如下所示,root project 包含了subproject01、subproject02、subproject03三个子项目。
在这里插入图片描述
在IDEA创建对应项目工程树的项目如下所示:
在这里插入图片描述

settings.gradle文件里面主要定义了当前 gradle 项目及子 project 的项目名称。settings.gradle对应gradle中的实例: org.gradle.api.initialization.Settings 。

在这里插入图片描述

每个项目只有一个 settings 文件。一个子工程只有在 setting 文件中配置了才会被 gradle 识别,这样在构建的时候才会被包含进去。作为开发者我们只需要关注该文件中的 include 方法即可。使用相对路径【 : 】引入子工程。配置示例如下所示:

//根工程项目名 
rootProject.name = 'root' 
//包含的子工程名称 
include 'subject01' 
include 'subject02' 
include 'subject03' 
//包含的子工程下的子工程名称
include 'subject01:subproject011' 
include 'subject01:subproject012'

项目名称中 “:” 代表项目的分隔符, 类似路径中的 “/”. 如果以 “:” 开头则表示相对于 root project (第一层 “:” 开头是可有可无得)。然后 Gradle 会为每个带有 build.gradle 脚本文件的工程构建一个与之对应的 Project 对象。

3 Task任务

一个项目中可以在build.gradle中定义多个任务,一个项目是一个Project对象,而项目实质上是 Task 对象的集合。一个 Task 表示一个逻辑上较为独立的执行过程,比如编译 Java 源代码,拷贝文件, 打包 Jar 文件,甚至可以是执行一个系统命令。另外,一个 Task 可以读取和设置 Project 的 Property 以完成特定的操作。

可参考官方文档:https://docs.gradle.org/current/userguide/tutorial_using_tasks.html

在root的build.gradle文件定义任务,例子:

task task1{//任务的配置段println "root task1"//任务的配置段doFirst(){ println "root task1 doFirst" }doLast(){ println "root task1 doLast" }
}

在文件所在的目录执行命令: gradle -i task1。 执行结果如下:

在这里插入图片描述

task 的配置段是在配置阶段完成。task 的 doFirst、doLast 方法是执行阶段完成,并且 doFirst 在 doLast 执行之前执行。

区分任务的配置段和任务的行为:任务的配置段在配置阶段执行,任务的行为在执行阶段执行

3.1 任务的行为

doFirst、doLast 两个方法可以在任务内部定义,也可以在任务外部定义。上面的例子是在任务内部定义,下面添加在任务外部定义:

task task1 {//任务的配置段println "root task1"//任务的配置段doFirst() { println "root task1 doFirst" }doLast() { println "root task1 doLast" }
}task1.doFirst() { println "root task1 doFirst outer" }
task1.doLast() { println "root task1 doLast outer" }

在文件所在的目录执行命令: gradle -i task1。 执行结果如下:

在这里插入图片描述

在上面的基础上再添加action行为

def map = new HashMap<String, Object>();
//action属性可以设置为闭包,设置task自身的行为
map.put("action", { println "do some action" })task (map, "task1") {//任务的配置段println "root task1"//任务的配置段doFirst() { println "root task1 doFirst" }doLast() { println "root task1 doLast" }
}task1.doFirst() { println "root task1 doFirst outer" }
task1.doLast() { println "root task1 doLast outer" }

在文件所在的目录执行命令: gradle -i task1。 执行结果如下:

在这里插入图片描述

底层原理分析:

无论是定义任务自身的 action,还是添加的 doLast、doFirst 方法,其实底层都被放入到一个 Action 的 List 中了,最初这个 action List 是空的,当我们设置了 action【任务自身的行为】,它先将 action 添加到列表中,此时列表只有一个 action,后续执行doFirst 的时候 doFirst 在 action 前面添加,执行 doLast 的时候 doLast 在 action 后面添加。

doFirst 永远添加在 actions List 的第一位,保证添加的 Action 在现有的 action List 元素的最前面;doLast 永远都是在 action List 末尾添加,保证其添加的 Action 在现有的 action List 元素的最后面。一个往前面添加,一个往后面添加,最后这个 action List 就按顺序形成了 doFirst、doSelf、doLast 三部分的 Actions,就达到 doFirst、doSelf、doLast 三部分的 Actions 顺序执行的目的

在gradle 5.X之前,可以用<<代表 doLast,在 gradle5.x 版本之后就废弃,不能使用了,如下所示:

task hello << { println 'Hello world!' }

3.2 任务依赖方式

Task 之间的依赖关系可以在以下几部分设置:

  1. 参数依赖
  2. 内部依赖
  3. 外部依赖

声明任务的时候对任务名可以用单引号,双引号,或者单引号和双引号都不用。

3.2.1 参数方式依赖
task A { doLast { println "TaskA.." } }
task 'B' { doLast { println "TaskB.." } }
//参数方式依赖: dependsOn后面用冒号
task 'C'(dependsOn: ['A', 'B']) { doLast { println "TaskC.." } }

在文件所在的目录执行命令: gradle -i C。 执行结果如下:
在这里插入图片描述

3.2.2 内部依赖

内部依赖的示例

task A { doLast { println "TaskA.." } }
task 'B' { doLast { println "TaskB.." } }
//参数方式依赖 
task 'C' {//内部依赖:dependsOn后面用 = 号 dependsOn = [A, B]doLast { println "TaskC.." }
}
3.2.3 外部依赖

外部依赖的示例

task A { doLast { println "TaskA.." } }
task 'B' { doLast { println "TaskB.." } }task 'C' {doLast { println "TaskC.." }
}
//外部依赖:可变参数,引号可加可不加 
C.dependsOn(B,'A')
3.2.4 跨项目依赖

task 也持跨项目依赖 在 subject01 工程的 build.gradle 文件中定义

task A { doLast { println "subject01.TaskA.." } }

在 subject02 工程的 build.gradle 文件中定义:

task B {dependsOn(":subject01:A")
//依赖根工程下的subject01中的任务A :跨项目依赖。doLast { println "subject02.TaskB.." }
}

在文件所在的目录执行命令: gradle -i B。 执行结果如下:

在这里插入图片描述
另外一些任务依赖的规则说明:

  • 当一个 Task 依赖多个 Task 的时候,被依赖的 Task 之间如果没有依赖关系,那么它们的执行顺序是随机的
  • 重复依赖的任务只会执行一次,比如: A->B、C ,B->C .任务 A 依赖任务 B 和任务 C、任务 B 依赖 C 任务。执行任务 A 的时候,显然任务 C 被重复依赖了,C 只会执行一次。

3.3 执行任务的命令与参数

任务执行语法:gradle [taskName...] [--option-name...]

在这里插入图片描述
在这里插入图片描述

更详细的命令请参考官方文档:
https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_executing_tasks

拓展:gradle 任务名可以缩写用 : 符号, 任务名支持驼峰式命名风格的任务名缩写。

如:任务名connectTask 简写为:cT,执行任务 gradle cT

前面提到的 Gradle 指令本质:一个个的 task任务, Gradle 中所有操作都是基于任务完成的。

gradle 默认各指令之间相互的依赖关系
在这里插入图片描述
相关说明:
在这里插入图片描述

3.4 任务定义方式

任务定义方式,总体分为两大类:

  • 通过 Project 中的 task()方法,
  • 通过 tasks 对象的 create 或者 register 方法
3.4.1 task方法
//任务名称,闭包都作为参数
task('A', {println "taskA..."
})
//闭包作为最后一个参数可以直接从括号中拿出来
task('B') {println "taskB..."
}
//groovy语法支持省略方法括号:上面三种本质是一种 
task C {println "taskC..."
}def map = new HashMap<String, Object>();
map.put("action", { println "taskD.." })
//action属性可以设置为闭包 
task(map,"D"); 
3.4.2 create和register 方法
// 使用tasks的create方法 
tasks.create('E') {println "taskE.."
}
tasks.register('F') {println "taskF...."
}

执行gradle build 查看执行结果
在这里插入图片描述
taskD没有被执行是因为action只有在执行任务的时候才触发,而taskF没有输出信息是因为taskF是用
register方法的定义方式,任务执行的是延迟创建,也即只有当task被需要使用的时候才会被创建。

gradle F 需要指定执行任务的才会被触发
在这里插入图片描述

我们可以在定义任务的同时指定任务的属性,具体属性有:
在这里插入图片描述
在定义任务时也可以给任务分配属性:定义任务的时候可以直接指定任务属性,也可以给已有的任务动态分配属性:

//①.H是任务名,前面通过具名参数给map的属性赋值,以参数方式指定任务的属性信息
task(group: "testGroup", description: "this is task B", "H")
// ②.G是任务名,定义任务的同时,在内部直接指定属性信息
task("G") {group("testGroup") description("this is the task G") 
}
// ③.I是任务名,给已有的任务 在外部直接指定属性信息
task "I" {}
I.group = "testGroup"
// 案例:给已有的clean任务重新指定组信息
clean.group("testGroup")

删除Gradle,新增加了任务分组testGroup
在这里插入图片描述

3.5 任务类型

3.5.1 常见任务类型

前面我们定义的 task 都是 DefaultTask 类型的,Gradle 官网给出了一些现成的任务类型帮助我们快速完成想要的任务,我们只需要在创建任务的时候,指定当前任务的类型即可,然后即可使用这种类型中的属性和 API 方法了。

在这里插入图片描述

如果想看更详细的 gradle 自带 Task 类型,请参考官方文档:https://docs.gradle.org/current/dsl/index.html 官方文档在给出这些任务类型的时候,同时给出了案例代码,可以点进去上述官网地址中的某个类型中观看

3.5.2 自定义Task类型

自定义任务类型CustomTask 如下所示:

class CustomTask extends DefaultTask {
//@TaskAction表示Task本身要执行的方法 @TaskActiondef doSelf() { println "Task 自身 在执行的in doSelf" }
}def myTask = task MyDefinitionTask(type: CustomTask)
myTask.doFirst() { println "task 执行之前 执行的 doFirst方法" }
myTask.doLast() { println "task 执行之后 执行的 doLast方法" }

控制台执行命令验证:gradle MyDefinitionTask
在这里插入图片描述

3.6 任务执行顺序

在 Gradle 中,有三种方式可以指定 Task 执行顺序:

  1. dependsOn 强依赖方式
  2. 通过 Task 输入输出
  3. 通过 API 指定执行顺序

详细请参考官网:https://docs.gradle.org/current/dsl/org.gradle.api.Task.html

3.7 动态分配任务

gradle 的强大功能不仅仅用于定义任务的功能。例如,可以使用它在循环中注册同一类型的多个任务。

一旦注册了任务,就可以通过 API 访问它们。例如,您可以使用它在运行时动态地向任务添加依赖项。Ant 不允许这样 的事情发生。

构建 4 个任务,但是任务 0 必须依赖于任务 2 和 3,那么代表任务 2 和 3 需要在任务 0 之前优先加载。具体测试如下:

4.times {counter ->tasks.register("task$counter") {doLast { println "I'm task number $counter" }}
}
tasks.named('task0') {dependsOn('task2', 'task3')
}

构建 4 个任务,但是任务 0 必须依赖于任务 2 和 3,那么代表任务 2 和 3 需要在任务 0 之前优先加载。具体测试如下:
控制台执行命令验证:gradle task0

在这里插入图片描述

3.8 任务的关闭与开启

每个任务都有一个 enabled标志默认值为 true。将其设置为 false 阻止执行任何任务动作,禁用的任务将标记为“跳过”。

task disableMe {doLast { println 'This task is Executing...' }//直接设置任务开启,默认值为true enabled(true)
}
//设置关闭任务
disableMe.enabled = false 

设置enabled =false的前后对比,false的时候任务不执行
在这里插入图片描述

3.9 任务的超时

每个任务都有一个 timeout 可用于限制其执行时间的属性。当任务达到超时时,其任务执行线程将被中断。该任务将被标记为失败。终结器任务仍将运行。如果 --continue 使用,其他任务可以在此之后继续运行。不响应中断的任务无法超时。Gradle 的所有内置任务均会及时响应超时。

在控制台使用: gradle a b 测试会发现执行 a 的时候,由于 a 执行超时,抛出异常,所以没有继续往下执行【b 也没执行】。 然后在控制台使用: gradle a b –continue,测试会发现 a 虽然执行失败,但是 b 还是执行了。

task a() {doLast {Thread.sleep(1000)println "当前任务a执行了"}timeout = Duration.ofMillis(500)
}
task b() {doLast {println "当前任务b执行了"}
}

在控制台使用: gradle a b 测试会发现执行 a 的时候,由于 a 执行超时,抛出异常,所以没有继续往下执行【b 也没执行】。
在这里插入图片描述
在控制台使用: gradle a b –continue,测试会发现 a 虽然执行失败,但是 b 还是执行了。

在这里插入图片描述

3.10 任务的查找

常用的任务查找方法有:根据任务名查找和根据任务路径查找

根据任务名查找示例:

task searchTaskTest { doLast { println "searchTaskTest trigger doLast" } }
//根据任务名查找
tasks.findByName("searchTaskTest").doFirst({println "searchTaskTest trigger doFirst1"})
tasks.getByName("searchTaskTest").doFirst({println "searchTaskTest trigger doFirst2"})

在这里插入图片描述

根据任务路径查找示例:

task searchTaskTest { doLast { println "searchTaskTest trigger doLast" } }
// 根据任务路径查找【相对路径】
tasks.findByPath(":subject02:searchTaskTest").doFirst({println "searchTaskTest trigger doFirst1"})
tasks.getByPath(":subject02:searchTaskTest").doFirst({println "searchTaskTest trigger doFirst2"})

在这里插入图片描述

3.11 任务的规则

当我们执行、依赖一个不存在的任务时,Gradle 会执行失败,报错误信息。我们可以通过设置任务规则给每个任务加上默认的doLast行为,这样当执行一个不存在的任务时,就不是报错而是打印提示信息。此外还可以根据不同的规则动态创建需要的任务等情况。

task hello {doLast {println 'hello'}
}
tasks.addRule("对该规则的一个描述,便于调试、查看等"){String taskName -> task(taskName) {doLast {println "该${taskName}任务不存在,请查证后再执行"}}
}

测试: 使用 gradle abc hello 进行测试,此时当 abc 任务不存在时,也不会报异常【不中断执行】而是提示自定义的规则信息,继续执行 hello 任务。
在这里插入图片描述

3.12 任务的onlyIf断言

断言就是一个条件表达式。Task 有一个 onlyIf 方法。它接受一个闭包作为参数,如果该闭包返回 true 则该任务执行, 否则跳过。
在这里插入图片描述

这有很多用途,比如控制程序哪些情况下打什么包,什么时候执行单元测试,什么情况下执行单元测试的时候不执行网络测试等。具体案例如下所示:

task testOnlyIf {doLast {println 'testOnlyIf doLast'}
}
testOnlyIf.onlyIf {def property = project.hasProperty('abc123')return !property
}

当项目没有abc123属性的时候,该任务执行因为条件表达式为true
在这里插入图片描述

测试:通过-P 为 Project 添加 abc123 属性,当项目有abc123属性的时候,因为条件表达式为false,该任务不执行。

gradle testOnlyIf -Pabc123

在这里插入图片描述

3.13 默认的任务

Gradle 允许您定义一个或多个在没有指定其他任务时执行的默认任务。 代码如下所示:

defaultTasks 'myClean', 'myRun'
tasks.register('myClean'){doLast {println 'Default Cleaning!' }
}
tasks.register('myRun') {doLast {println 'Default Running!' }
}
tasks.register('other') {doLast {println "I'm not a default task!" }
}

测试执行
在这里插入图片描述


文章转载自:

http://cQhORhqW.zwfbn.cn
http://Je2uPlPW.zwfbn.cn
http://IbmOtIgq.zwfbn.cn
http://wKYIrWB0.zwfbn.cn
http://gb59X5wB.zwfbn.cn
http://tcmTzeOw.zwfbn.cn
http://3TxBxqC1.zwfbn.cn
http://PYIOpi4B.zwfbn.cn
http://MKjNH2vD.zwfbn.cn
http://cHTxgwdV.zwfbn.cn
http://h1T27G8X.zwfbn.cn
http://ZsIk2CwZ.zwfbn.cn
http://lu4ca04W.zwfbn.cn
http://EVOYRiSf.zwfbn.cn
http://IyT1iODj.zwfbn.cn
http://g2Rr2irD.zwfbn.cn
http://lnTJP0Xz.zwfbn.cn
http://bEMYVnnj.zwfbn.cn
http://s6VOBS2p.zwfbn.cn
http://vnFi8pJ8.zwfbn.cn
http://s7wK9XsJ.zwfbn.cn
http://TSXNbXnC.zwfbn.cn
http://dngAZwGY.zwfbn.cn
http://IHpIzuUU.zwfbn.cn
http://SlZk2keh.zwfbn.cn
http://nnKINFct.zwfbn.cn
http://CCJK0Jsh.zwfbn.cn
http://d28gQuGN.zwfbn.cn
http://vxc8CFqe.zwfbn.cn
http://1gMffsOS.zwfbn.cn
http://www.dtcms.com/a/377910.html

相关文章:

  • 强大的鸿蒙HarmonyOS网络调试工具PageSpy 介绍及使用
  • C++/QT 1
  • 软件测试用例详解
  • 【ROS2】基础概念-进阶篇
  • 三甲地市级医院数据仓湖数智化建设路径与编程工具选型研究(上)
  • 利用Rancher平台搭建Swarm集群
  • BRepMesh_IncrementalMesh 重构生效问题
  • VRRP 多节点工作原理
  • 运行 Ux_Host_HUB_HID_MSC 通过 Hub 连接 U 盘读写不稳定问题分析 LAT1511
  • Oracle体系结构-控制文件(Control Files)
  • 0303 【软考高项】项目管理概述 - 组织系统(项目型组织、职能型组织、矩阵型组织)
  • Spark-SQL任务提交方式
  • 10、向量与矩阵基础 - 深度学习的数学语言
  • 开发避坑指南(45):Java Stream 求两个List的元素交集
  • React19 中的交互操作
  • 阿里云ECS vs 腾讯云CVM:2核4G服务器性能实测对比 (2025)
  • 网络编程;TCP多进程并发服务器;TCP多线程并发服务器;TCP网络聊天室和UDP网络聊天室;后面两个还没写出来;0911
  • STM32项目分享:基于stm32的室内环境监测装置设计与实现
  • 利用归并算法对链表进行排序
  • GPU 服务器压力测试核心工具全解析:gpu-burn、cpu-burn 与 CUDA Samples
  • Power Automate List Rows使用Fetchxml查询的一个bug
  • Zynq开发实践(FPGA之ddr sdram读写)
  • LeetCode 热题 160.相交链表(双指针)
  • 西门子 S7-200 SMART PLC 编程:转换 / 定时器 / 计数器指令详解 + 实战案例(案例篇)
  • SAM-Med3D:面向三维医疗体数据的通用分割模型(文献精读)
  • 考研复习-计算机网络-第五章-传输层
  • win11安装jdk8-u211-windows
  • 从传统到智能:3D 建模流程的演进与 AI 趋势 —— 以 Blender 为例
  • 开发避坑指南(46):Java Stream 对List的BigDecimal字段进行求和
  • 在OpenHarmony上适配图形显示【3】——添加显示接口类型