2024-07-30
为了终止绝望的连锁,希望她能化为照亮正确道路的灯火。 --- 《Re:从零开始的异世界生活》 · 酷儿
Gradle闭包
这段代码是Java中的一个方法定义,具体来说是一个使用Groovy DSL编写的Gradle插件中的一部分。它利用了Groovy语言中的闭包(Closure)和委托(Delegate)机制。我们来详细解释一下这段代码的各个部分:
public void forcedTypes(@DelegatesTo(ForcedTypesHandler.class) Closure<?> closure) {
closure.setDelegate(this.forcedTypes);
closure.setResolveStrategy(1);
closure.call();
}
代码解析
-
方法签名
public void forcedTypes(@DelegatesTo(ForcedTypesHandler.class) Closure<?> closure)public void forcedTypes(...): 定义了一个名为forcedTypes的公开方法,没有返回值。@DelegatesTo(ForcedTypesHandler.class) Closure<?> closure: 参数是一个Groovy的闭包对象,并使用了@DelegatesTo注解,指明这个闭包的委托对象是ForcedTypesHandler类型。
-
闭包的委 托设置
closure.setDelegate(this.forcedTypes);closure.setDelegate(...): 设置闭包的委托对象。委托对象是this.forcedTypes,表示当前对象的forcedTypes属性。
-
闭包的解析策略设置
closure.setResolveStrategy(1);closure.setResolveStrategy(...): 设置闭包的解析策略。这里的解析策略被设置为1,表示DELEGATE_FIRST,即在闭包中优先解析委托对象的属性和方法。
-
调用闭包
closure.call();closure.call(): 调用闭包。
解释和应用场景
这段代码通常出现在Gradle插件的DSL定义中,允许用户在构建脚本中使用更简洁和直观的语法来配置forcedTypes。具体来说,当用户在Gradle脚本中调用forcedTypes { ... }时,传递给该方法的闭包会被动态绑定到forcedTypes对象上,并且闭包内的代码会优先解析forcedTypes对象的属性和方法。这使得用户可以直接在闭包内配置forcedTypes,例如:
forcedTypes {
type {
name = 'VARCHAR'
expression = '.*'
}
}
在这 个示例中,forcedTypes闭包中的配置会被应用到forcedTypes对象上,简化了配置过程。
总结
这段代码通过设置闭包的委托对象和解析策略,实现了DSL的灵活配置,使得用户可以在Groovy脚本中以更自然的方式配置forcedTypes。这种模式在Gradle插件开发中非常常见,有助于提高代码的可读性和可维护性。
Gradle插件中动态添加依赖项
这段代码是一个用来在Gradle插件中动态添加依赖项的例子。它通过调用project.getDependencies().addProvider方法,将某个依赖项添加到特定的配置中。我们来详细解析一下这段代码:
project.getDependencies().addProvider(
sourceSet.getImplementationConfigurationName(),
jooqExtension.getEdition().map(e -> e.getGroupId() + ":jooq")
.flatMap(ga -> jooqExtension.getVersion().map(v -> ga + ":" + v))
);
代码解析
-
获取配置名称
sourceSet.getImplementationConfigurationName()sourceSet.getImplementationConfigurationName():获取sourceSet的实现配置名称。sourceSet通常表示的是Gradle项目的某个源码集(如main、test等),而实现配置名称一般是类似于implementation的字符串(如mainImplementation)。
-
构建依赖项字符串
jooqExtension.getEdition().map(e -> e.getGroupId() + ":jooq")
.flatMap(ga -> jooqExtension.getVersion().map(v -> ga + ":" + v))jooqExtension.getEdition():获取jooqExtension的Edition属性,这是一个Provider对象。.map(e -> e.getGroupId() + ":jooq"):将Edition对象映射为其GroupId与"jooq"的拼接字符串。.flatMap(ga -> jooqExtension.getVersion().map(v -> ga + ":" + v)):将前一步得到的GroupId和"jooq"的字符串与Version属性拼接,形成完整的依赖项坐标字符串(例如,org.jooq:jooq:3.14.8)。
-
添加依赖项
project.getDependencies().addProvider(...);project.getDependencies().addProvider:这是Gradle的一个方法,用来将动态提供的依赖项添加到特定配置中。- 第一个参数是依赖项要添加到的配置名称,这里是通过
sourceSet.getImplementationConfigurationName()获取的。 - 第二个参数是依赖项的坐标字符串,是通过
jooqExtension的Edition和Version属性动态生成的。
依赖项的添加位置
这段代码中的依赖项是添加到插件所管理的项目中的,而不是插件自身的依赖。具体来说:
project.getDependencies().addProvider方法将依赖项添加到指定的项目配置中(例如implementation配置)。sourceSet表示的是使用插件的项目的源码集,因此依赖项是添加到这个项目的实现配置中。
依赖项添加的总结
总结来说,这段代码通过动态获取jooqExtension的Edition和Version属性,生成依赖项的坐标字符串,并将该依赖项添加到使用该插件的项目的实现配置中。这种方式允许插件用户通过配置jooqExtension来灵活地管理他们的项目依赖,而不需要直接在构建脚本中手动添加依赖项。
Gradle Property.finalizeValueOnRead()
在Gradle中,Property接口提供了一种灵活且类型安全的方式来处理属性。finalizeValueOnRead()方法是Property接口中的一个方法,用于控制属性值的生命周期和变化。
代码解析
private final Property<String> version;
private final Property<JooqEdition> edition;
- 这两行定义了两个私有的最终属性,分别是
version和edition。它们的类型是Property,这是Gradle提供的用于处理属性的接口。
version.finalizeValueOnRead();
edition.finalizeValueOnRead();
finalizeValueOnRead()方法被调用在这两个属性上。这个方法的作用是在属性被读取时将其值固定下来,不再允许修改。
finalizeValueOnRead()的作用
finalizeValueOnRead()方法的主要作用是控制属性值的可变性。具体来说:
- 固定属性值:一旦属性值被读取,它就会被固定(finalized)。这意味着在第一次读取之后,属性的值不能再被改变。
- 确保一致性:在某些情况下,你希望确保属性值一旦被使用,就不会再发生变化。这对于确保配置的一致性和防止潜在的并发修改是非常有用的。
- 防止后续修改:调用
finalizeValueOnRead()后,如果尝试在属性被读取后修改它的值,会抛出异常。这有助于捕获和避免不期望的修改。
使用场景
这种方法通常在以下场景中使用:
- 延迟初始化:属性值可能在插件或任务的执行过程中动态计算或设置。在属性被读取之前,值可以是可变的。
- 配置锁定:在读取配置值之后锁定它,防止后续的配置变化对任务执行产生影响。
- 确保安全性:在多线程环境中,确保某个属性一旦被读取就不会再被其他线程修改,避免并发问题。
示例
public class MyPluginExtension {
private final Property<String> version;
private final Property<JooqEdition> edition;
@Inject
public MyPluginExtension(ObjectFactory objects) {
this.version = objects.property(String.class);
this.edition = objects.property(JooqEdition.class);
version.finalizeValueOnRead();
edition.finalizeValueOnRead();
}
// Getter and setter methods
public Property<String> getVersion() {
return version;
}
public Property<JooqEdition> getEdition() {
return edition;
}
}