TL;博士;
基本上在 gradle 源中有一个类似这样的方法:
public Object sourceSets(Closure closure) {
// do stuff like configuring the closure
closure.call()
}
所以当你打电话时:
sourceSets {
some code
}
(顺便说一句,这与 call 相同sourceSets({ some code })
,只是去掉了括号,这在 groovy 中是可以的)
sourceSets
调用该方法时,“某些代码”不会立即执行。Gradle 可以选择在他们决定何时执行它。具体来说,他们可以(并且确实)在实际执行闭包之前配置所有者和委托等内容。
更长的版本
原来文件中的sourceSets
方法build.gradle
实际上是由插件添加的,例如 java/kotlin/groovy 插件。
作为示例,我们可以查看 java 插件和DefaultJavaPluginConvention 类,它具有以下代码:
private final SourceSetContainer sourceSets;
@Override
public Object sourceSets(Closure closure) {
return sourceSets.configure(closure);
}
sourceSets { ... }
这是在您输入build.gradle
文件时调用的方法。它获得了闭包并继续将其交给configure
源集容器的方法。请注意,我们还没有执行闭包,我们只是将它作为未执行的代码块传递。
如果我们稍微挖掘一下,我们会发现AbstractNamedDomainObjectContainer 类configure
中的方法:
public AbstractNamedDomainObjectContainer<T> configure(Closure configureClosure) {
ConfigureDelegate delegate = createConfigureDelegate(configureClosure);
ConfigureUtil.configureSelf(configureClosure, this, delegate);
return this;
}
(SourceSetContainer
是一个接口,实现类继承自AbstractNamedDomainObjectContainer
...这是正确的configure
方法)
其中ConfigureUtil具有以下代码:
public static <T> T configureSelf(@Nullable Closure configureClosure, T target, ConfigureDelegate closureDelegate) {
if (configureClosure == null) {
return target;
}
configureTarget(configureClosure, target, closureDelegate);
return target;
}
private static <T> void configureTarget(Closure configureClosure, T target, ConfigureDelegate closureDelegate) {
if (!(configureClosure instanceof GeneratedClosure)) {
new ClosureBackedAction<T>(configureClosure, Closure.DELEGATE_FIRST, false).execute(target);
return;
}
// Hackery to make closure execution faster, by short-circuiting the expensive property and method lookup on Closure
Closure withNewOwner = configureClosure.rehydrate(target, closureDelegate, configureClosure.getThisObject());
new ClosureBackedAction<T>(withNewOwner, Closure.OWNER_ONLY, false).execute(target);
}
其中相关部分是对groovy Closure rehydrate方法的调用,根据文档执行以下操作:
Returns a copy of this closure for which the delegate, owner and thisObject are replaced with the supplied parameters. Use this when you want to rehydrate a closure which has been made serializable thanks to the dehydrate() method.
只有在configureTarget
方法的最后一行,gradle 才会调用execute
为表示闭包而创建的动作。所以闭包的执行是在根据 gradle 需要配置了 owner、delegate 和 this 指针之后完成的。