配置脚本的最终目的,是运行对应的task。在脚本中定义task可理解为定义一个java类,Gradle运行时会根据需要创建task instance。有两个重要的类可供参考:
TaskContainer
。project instances中的tasks
属性,保存运行时生成的task instance。Task
。Task接口定义
Type
这样定义一个新的tasks时:
tasks.register('hello') { doLast { println 'hello' } }
相当于注册了一个匿名的task类,该task运行时生成的实例是’hello‘。这个task不存在复用的可能性。
但我们可以自定义有名称的Task:
abstract class GreetingTask extends DefaultTask { @TaskAction def greet() { println 'hello from GreetingTask' } }
创建了一个有名称可复用的GreetingTask。这种可复用的task叫做Task type。
基于给定Type创建一个新的Task ‘hello’,这个task继承了GreetingTask的属性和方法
// Create a task using the task type tasks.register('hello', GreetingTask)
Gradle内置了许多Task types,可使用系统自带的Task type
//copy task继承自Copy,可以使用Copy中的from ,into等方法 def copy = tasks.register('copy', Copy) { from(file('srcDir')) into(buildDir) }
Configure task
task可以有好几种配置方式:
//定义时配置 tasks.register('task2'){ println "configured by register" } //通过named名字配置 def reftask2 = tasks.named('task2'){ println "configured by tasks.named" } //通过引用配置 reftask2.configure{ println "configured by reference" } //直接通过名字配置 task2{ println "configured by task name" }
观察一下输出,几个配置都生效了:
$ gradle task2 Configuration on demand is an incubating feature. configured by register configured by tasks.named configured by reference configured by task name BUILD SUCCESSFUL in 1s
Dependency and DAG
Task之间可以指定依赖。比如task X依赖于task Y, 则运行task X时,会先执行task Y
def taskX = tasks.register('taskX') { doLast { println 'taskX' } } def taskY = tasks.register('taskY') { doLast { println 'taskY' } } taskX.configure { dependsOn taskY }
检查某个task的依赖:
gradle taskName -m
一个task可以有多个依赖,因为依赖的存在,所有的task就形成了一颗DAG树,这是从Gradle官网扒过来的例子:

DAG, Directed Acyclic Graphs,有向无环图。这种图的特征是:
- 从根节点往前遍历,每一条路都可以直达尾节点,不会成环
- 从尾节点往回追溯,可以回到根节点,不会成环
- 从根节点到尾节点之间的各路径之间,存在重复或交叉
Task rules
Task其他属性都很好理解,有兴趣的可以自己去扒官网,其中烧脑一点的是Task rules。
正常情况下,gradle的使用都是
gradle taskname
正常运行的前提是要求task必须存在。
如果用户输入一个不存在的task,你想动态创建并运行该task的时候,就使用task rules
比如说你管理100台机器,需要创建100个task,这些task的名字分别是pingServer1..pingServer100,你不想手动写这么多task,你可以利用task rules动态创建:
//如果task不存在就进入task rules tasks.addRule("Pattern: ping<ID>") { String taskName -> if (taskName.startsWith("ping")) { //动态创建task task(taskName) { println "Pinging: " + (taskName - 'ping') } } }
然后你就可以调用这些一开始并不存在的task了,这些task被调用后会进入task rules,然后被动态创建,然后被执行:
$ gradle pingServer1 Configuration on demand is an incubating feature. Pinging: Server1 $ gradle pingServer100 Configuration on demand is an incubating feature. Pinging: Server100 BUILD SUCCESSFUL in 929ms
通过task rules动态创建的task可以被其他task正常使用,比如说这样,新建一个groupPing task,依赖于task rules创建的pingServer1和pingServer2
tasks.register('groupPing') { dependsOn 'pingServer1', 'pingServer2' }
lifecycle task
lifecycle我们都知道,是编译步骤的一个分组,比如maven就有clean, default和site三个lifecycle
Gradle里面的lifecycle这个概念非常的弱。并不像maven一样,强调lifecycle和phase,可以自定义lifecycle。
Gradle由于Task DAG的存在,可以方便的创建工作流,只需要指定 依赖关系就可以。因此Grade引入了一种特殊的task,叫做lifecyle task。事实上,lifecycle task基本上是一个空的task。当你把这个空的task依赖到一堆有实际意义的task上时,运行这个空task就可以调用它依赖的所有task。
比如说我们常用的命令,gradle build。这个build就是一个lifecycle task。它本身什么都不做,但是他会依赖于一大堆task:
$ gradle build -m Configuration on demand is an incubating feature. :app:compileJava SKIPPED :app:processResources SKIPPED :app:classes SKIPPED :app:jar SKIPPED :app:startScripts SKIPPED :app:distTar SKIPPED :app:distZip SKIPPED :app:assemble SKIPPED :app:compileTestJava SKIPPED :app:processTestResources SKIPPED :app:testClasses SKIPPED :app:test SKIPPED :app:check SKIPPED :app:build SKIPPED
因此当我们调用build的时候,是执行了它前面的那些task,从compoileJava一直执行到check。
Gradle的Base Plugin定义了一些标准的lifecycle tasks:standard lifecycle tasks, 比如build , assembe ,check等。但具体的工作是用户引入的Plugin提供的,Plugin给这些lifecycly task添加依赖,引入task,最终可以执行完整的工作流。
比如上面的build task,是在Base Plugin中定义的,但什么都不会做。当我们使用java application plugin的时候,才会由java application plugin引入了具体的tasks间依赖关系。才会有grade build正常执行
回复 can you buy generic cytotec 取消回复