深入理解gradle中的task
深入理解gradle中的task
简介
在之前的文章中,我们讲到了如何使用gradle创建一个简单的task,以及task之间怎么依赖,甚至使用了程序来创建task。在本文中,我们会更加深入的去了解一下gradle中的task。
定义task
定义一个task可以有很多种方式,比如下面的使用string作为task的名字:
task('hello') {
doLast {
println "hello"
}
}
task('copy', type: Copy) {
from(file('srcDir'))
into(buildDir)
}
还可以使用tasks容器来创建:
tasks.create('hello') {
doLast {
println "hello"
}
}
tasks.create('copy', Copy) {
from(file('srcDir'))
into(buildDir)
}
上面的例子中,我们使用tasks.create方法,将新创建的task加到tasks集合中。
我们还可以使用groovy特有的语法来定义一个task:
task(hello) {
doLast {
println "hello"
}
}
task(copy, type: Copy) {
from(file('srcDir'))
into(buildDir)
}
tasks 集合类
上面我们在创建task的时候,使用了tasks集合类来创建task。
实际上,tasks集合类是一个非常有用的工具类,我们可以使用它来做很多事情。
直接在build文件中使用tasks,实际上是引用了TaskContainer的一个实例对象。我们还可以使用 Project.getTasks()
来获取这个实例对象。
我们看下TaskContainer的定义:
public interface TaskContainer extends TaskCollection<Task>, PolymorphicDomainObjectContainer<Task>
从定义上,我们可以看出TaskContainer是一个task的集合和域对象的集合。
taskContainer中有四类非常重要的方法:
第一类是定位task的方法,有个分别是findByPath和getByPath。两个方法的区别就是findByPath如果没找到会返回null,而getByPath没找到的话会抛出UnknownTaskException。
看下怎么使用:
task hello
println tasks.getByPath('hello').path
println tasks.getByPath(':hello').path
输出:
:hello
:hello
第二类是创建task的方法create,create方法有多种实现,你可以直接通过名字来创建一个task:
task('hello') {
doLast {
println "hello"
}
}
也可以创建特定类型的task:
task('copy', type: Copy) {
from(file('srcDir'))
into(buildDir)
}
还可以创建带参数的构造函数的task:
class CustomTask extends DefaultTask {
final String message
final int number
@Inject
CustomTask(String message, int number) {
this.message = message
this.number = number
}
}
上面我们为CustomTask创建了一个带参数的构造函数,注意,这里需要带上@javax.inject.Inject注解,表示我们后面可以传递参数给这个构造函数。
我们可以这样使用:
tasks.create('myTask', CustomTask, 'hello', 42)
也可以这样使用:
task myTask(type: CustomTask, constructorArgs: ['hello', 42])
第三类是register,register也是用来创建新的task的,不过register执行的是延迟创建。也就是说只有当task被需要使用的时候才会被创建。
我们先看一个register方法的定义:
TaskProvider<Task> register(String name,
Action<? super Task> configurationAction)
throws InvalidUserDataException
可以看到register返回了一个TaskProvider,有点像java多线程中的callable,当我们调用Provider.get()获取task值的时候,才会去创建这个task。
或者我们调用TaskCollection.getByName(java.lang.String)的时候也会创建对应的task。
最后一类是replace方法:
Task replace(String name)
<T extends Task> T replace(String name,
Class<T> type)
replace的作用就是创建一个新的task,并且替换掉同样名字的老的task。
Task 之间的依赖
task之间的依赖关系是通过task name来决定的。我们可以在同一个项目中做task之间的依赖:
task hello {
doLast {
println 'Hello www.flydean.com!'
}
}
task intro {
dependsOn hello
doLast {
println "I'm flydean"
}
}
也可以跨项目进行task的依赖,如果是跨项目的task依赖的话,需要制定task的路径:
project('project-a') {
task taskX {
dependsOn ':project-b:taskY'
doLast {
println 'taskX'
}
}
}
project('project-b') {
task taskY {
doLast {
println 'taskY'
}
}
}
或者我们可以在定义好task之后,再处理task之间的依赖关系:
task taskX {
doLast {
println 'taskX'
}
}
task taskY {
doLast {
println 'taskY'
}
}
还可以动态添加依赖关系:
task taskX {
doLast {
println 'taskX'
}
}
// Using a Groovy Closure
taskX.dependsOn {
tasks.findAll { task -> task.name.startsWith('lib') }
}
task lib1 {
doLast {
println 'lib1'
}
}
task lib2 {
doLast {
println 'lib2'
}
}
task notALib {
doLast {
println 'notALib'
}
}
定义task之间的顺序
有时候我们的task之间是有执行顺序的,我们称之为对task的排序ordering。
先看一下ordering和dependency有什么区别。dependency表示的是一种强依赖关系,如果taskA依赖于taskB,那么执行taskA的时候一定要先执行taskB。
而ordering则是一种并不太强列的顺序关系。表示taskA需要在taskB之后执行,但是taskB不执行也可以。
在gradle中有两种order:分别是must run after和should run after。
taskA.mustRunAfter(taskB)表示必须遵守的顺序关系,而taskA.shouldRunAfter(taskB)则不是必须的,在下面两种情况下可以忽略这样的顺序关系:
第一种情况是如果shouldRunAfter引入了order循环的时候。
第二种情况是如果在并行执行的情况下,task所有的依赖关系都已经满足了,那么也会忽略这个顺序。
我们看下怎么使用:
task taskX {
doLast {
println 'flydean.com'
}
}
task taskY {
doLast {
println 'hello'
}
}
taskY.mustRunAfter taskX
//taskY.shouldRunAfter taskX
给task一些描述
我们可以给task一些描述信息,这样我们在执行gradle tasks的时候,就可以查看到:
task copy(type: Copy) {
description 'Copies the resource directory to the target directory.'
from 'resources'
into 'target'
include('**/*.txt', '**/*.xml', '**/*.properties')
}
task的条件执行
有时候我们需要根据build文件中的某些属性来判断是否执行特定的task,我们可以使用onlyIf :
task hello {
doLast {
println 'www.flydean.com'
}
}
hello.onlyIf { !project.hasProperty('skipHello') }
或者我们可以抛出StopExecutionException异常,如果遇到这个异常,那么task后面的任务将不会被执行:
task compile {
doLast {
println 'We are doing the compile.'
}
}
compile.doFirst {
if (true) { throw new StopExecutionException() }
}
task myTask {
dependsOn('compile')
doLast {
println 'I am not affected'
}
}
我们还可以启动和禁用task:
myTask.enabled = false
最后我们还可以让task超时,当超时的时候,执行task的线程将会被中断,并且task将会被标记为failed。
如果我们想继续执行,那么可以使用 --continue。
注意, 只有能够响应中断的task,timeout才有用。
task hangingTask() {
doLast {
Thread.sleep(100000)
}
timeout = Duration.ofMillis(500)
}
task rule
如果我们想要给某些task定义一些规则,那么可以使用tasks.addRule:
tasks.addRule("Pattern: ping<ID>") { String taskName ->
if (taskName.startsWith("ping")) {
task(taskName) {
doLast {
println "Pinging: " + (taskName - 'ping')
}
}
}
}
上我们定义了一个rule,如果taskName是以ping开头的话,那么将会输出对应的内容。
看下运行结果:
> gradle -q pingServer1
Pinging: Server1
我还可以将这些rules作为依赖项引入:
task groupPing {
dependsOn pingServer1, pingServer2
}
Finalizer tasks
和java中的finally一样,task也可以指定对应的finalize task:
task taskX {
doLast {
println 'taskX'
}
}
task taskY {
doLast {
println 'taskY'
}
}
taskX.finalizedBy taskY
> gradle -q taskX
taskX
taskY
finalize task是一定会被执行的,即使上面的taskX中抛出了异常。
总结
以上就是gradle中task的详解,希望大家能够喜欢。
本文已收录于 http://www.flydean.com/gradle-task-in-depth/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
深入理解gradle中的task的更多相关文章
- 【三】Gradle中的Task
gradle中,最经常被使用的,一个task,一个是dependencies 1.Task声明 task默认是DefaultTask类, Task中有两个属性 group description,最佳 ...
- 理解Flink中的Task和SUBTASK
1.概念 Task(任务):Task是一个阶段多个功能相同的subTask 的集合,类似于Spark中的TaskSet. subTask(子任务):subTask是Flink中任务最小执行单元,是一个 ...
- Gradle中的闭包
Gradle是基于Groovy的DSL基础上的构建工具,Gradle中的闭包,其原型上实际上即Groovy中闭包.而在表现形式上,其实,Gradle更多的是以约定和基于约定基础上的配置去展现.但本质上 ...
- storm源码之理解Storm中Worker、Executor、Task关系 + 并发度详解
本文导读: 1 Worker.Executor.task详解 2 配置拓扑的并发度 3 拓扑示例 4 动态配置拓扑并发度 Worker.Executor.Task详解: Storm在集群上运行一个To ...
- 深入理解gradle编译-Android基础篇
深入理解gradle编译-Android基础篇 导读 Gradle基于Groovy的特定领域语言(DSL)编写的一种自动化建构工具,Groovy作为一种高级语言由Java代码实现,本文将对Gradle ...
- 十分钟理解Gradle
一.什么是Gradle 简单的说,Gradle是一个构建工具,它是用来帮助我们构建app的,构建包括编译.打包等过程.我们可以为Gradle指定构建规则,然后它就会根据我们的“命令”自动为我们构建ap ...
- Gradle 1.12 翻译——第十七章. 从 Gradle 中调用 Ant
有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...
- Gradle之Android Gradle Plugin 主要 Task 分析(三)
[Android 修炼手册]Gradle 篇 -- Android Gradle Plugin 主要 Task 分析 预备知识 理解 gradle 的基本开发 了解 gradle task 和 plu ...
- gradle中使用嵌入式(embedded) tomcat, debug 启动
在gradle项目中使用embedded tomcat. 最开始部署项目需要手动将web项目打成war包,然后手动上传到tomcat的webapp下,然后启动tomcat来部署项目.这种手动工作通常还 ...
随机推荐
- 一文搞定全场景K3s离线安装
作者简介 王海龙,Rancher中国社区技术经理,负责Rancher中国技术社区的维护和运营.拥有6年的云计算领域经验,经历了OpenStack到Kubernetes的技术变革,无论底层操作系统Lin ...
- 自监督SOTA框架 | BYOL(优雅而简洁) | 2020
文章原创自微信公众号「机器学习炼丹术」 作者:炼丹兄 联系方式:微信cyx645016617 本篇文章主要讲解两个无监督2020年比较新比较火的论文: 论文名称:"Bootstrap You ...
- Model(metaclass=ModelBase)
Python装饰器.metaclass.abc模块学习笔记 - 王智愚 - 博客园 https://www.cnblogs.com/Security-Darren/p/4094959.html dja ...
- Linux 技巧:让进程在后台运行更可靠的几种方法
Linux 技巧:让进程在后台运行更可靠的几种方法 https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/index.html 我们经常会碰到这 ...
- Web下无插件播放rtsp视频流的方案及各家优秀内容资源整理
Web下无插件播放rtsp视频流的方案及各家优秀内容资源整理 方案一:服务器端用 websocket 接受 rtsp ,然后,推送至客户端 实现步骤: 方案二:使用 ffmpeg + nginx 把 ...
- 图的广度优先遍历算法(BFS)
在上一篇文章我们用java演示了图的数据结构以及图涉及到的深度优先遍历算法,本篇文章将继续演示图的广度优先遍历算法.广度优先遍历算法主要是采用了分层的思想进行数据搜索.其中也需要使用另外一种数据结构队 ...
- DEDECMS:修改DEDECMS会员中心发送邮件时,邮件内容里出现在DEDE链接
1.在member/index_do.php里,把文件里的 $mailbody .= "Power by http://www.dedecms.com 织梦内容管理系统!\r\n" ...
- DEDECMS:删除DEDE自带的织梦链方法
在include/taglib/flinktype.lib.php里删除掉如下代码: $dedecms = false; $dedecms->id = 999; $dedecms->typ ...
- WebApi Swagger 接口多版本控制 适用于APP接口管理
最近研究了下swagger多版本的维护,网上的文章千篇一律,无法满足我的需求,分享下我的使用场景以及实现 演示环境:Visual Studio 2019.Asp.NET WebAPI.NET Fram ...
- JVM之JVM体系结构
JVM是运行在操作系统之上的,它与硬件没有直接的交互 下图运行时数据区灰色代表线程私有,亮色(方法区和堆)代表所有线程共享. 1.类装载器ClassLoader 负责加载class文件,class文件 ...