以下代码使用 Gradle 5.4.1
task showDescription1 {
doLast {
description = 'this is task showDescription'
println description
}
}
task showDescription2 {
doLast {
println description
}
}
showDescription2.description = 'this is task showDescription'
task showDescription3 {
doLast {
println description
}
}
showDescription3 {
description = 'this is task showDescription'
}
以上 3 个 Task 完成的功能相同,即在执行这个 Task 时打印 description
属性。但是它们对 description
的赋值时,所在的生命周期却不同。
-
showDescription1
的赋值是在执行阶段 -
showDescription2
的赋值是在配置阶段 -
showDescription3
的赋值也是在配置阶段
事实上,对于每一个 Task,Gradle 都会在 Project 中创建一个同名的 Porperty,我们可以将该 Task 当做一个 Property 来访问,showDescription2
便是这种情况。另外,Gradle还会创建一个同名的方法,该方法接收一个闭包,我们可以通过该方法来配置 Task,showDescription3
便是这种情况。
这里面有两个概念:Groovy 中的 Bean 概念 和 Groovy 闭包的 delegate 机制。
Bean 概念
这个 Bean 概念与 Kotlin 中的 Data Class 差不多,即 Groovy 会自动生成属性的 getter()
, setter()
方法。所以上面我们可以直接访问 showDescription2
。
Delegate 机制
这里重点的是 Groovy 闭包的 Delegate 机制。简单来说,Delegate 机制可以使我们将一个闭包中的执行代码的作用对象设置成任意其他对象。
class Child {
private String name
}
class Parent {
Child child = new Child();
void configChild(Closure c) {
c.delegate = child
c.setResolveStrategy Closure.DELEGATE_FIRST
c()
}
}
def parent = new Parent()
parent.configChild {
name = "child name"
}
println parent.child.name
在上面的例子中,当我们调用 configChild()
时,我们并没有指明 name
属性是属于 Child
的,虽然它确实是设置的 Child.name
属性,但是从调用者来看,他传入闭包时,根本不知道 name
是属于哪个对象的。我们在 configChild
中做了手脚,使其不再访问 Parent
中的 name
(Parent
中也没有 name
属性),而是 Child
的 name
属性。
在 configChild()
方法中,我们将该方法接受的闭包的 delegate
设置为了 child
,然后将该闭包的 ResolveStrategy
设置为了 DELEGATE_FIRST
。这样,在调用 configChild()
时,所跟闭包中代码被代理到了 child
上,即这些代码实际上是在 child
上执行的。
再举个例子,
Project#configurations()
方法,实际上会将所跟闭包的delegate
设置成ConfigurationContainer
,然后在该ConfigurationContainer
上执行闭包中的代码。这里的ConfigurationContainer
也是Project
的一个属性。再比如,dependencies()
方法,该方法会将所跟闭包的delegate
设置成DependencyHandler
。
还有,Project
还定义了configure(Object object, Closure configureClosure)
方法,该方法是专门用来配置对象的(比如 Task),它会将configureClosure
的delegate
设置成object
,之后configureClosure
中的执行代码其实是在object
上执行的。
结论
Groovy 的 Delegate 机制的一个好处是可以增加所创建 DSL 的可读性。
网友评论