跳到主要内容

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();
}

代码解析

  1. 方法签名

    public void forcedTypes(@DelegatesTo(ForcedTypesHandler.class) Closure<?> closure)
    • public void forcedTypes(...): 定义了一个名为forcedTypes的公开方法,没有返回值。
    • @DelegatesTo(ForcedTypesHandler.class) Closure<?> closure: 参数是一个Groovy的闭包对象,并使用了@DelegatesTo注解,指明这个闭包的委托对象是ForcedTypesHandler类型。
  2. 闭包的委托设置

    closure.setDelegate(this.forcedTypes);
    • closure.setDelegate(...): 设置闭包的委托对象。委托对象是this.forcedTypes,表示当前对象的forcedTypes属性。
  3. 闭包的解析策略设置

    closure.setResolveStrategy(1);
    • closure.setResolveStrategy(...): 设置闭包的解析策略。这里的解析策略被设置为1,表示DELEGATE_FIRST,即在闭包中优先解析委托对象的属性和方法。
  4. 调用闭包

    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))
);

代码解析

  1. 获取配置名称

    sourceSet.getImplementationConfigurationName()
    • sourceSet.getImplementationConfigurationName():获取sourceSet的实现配置名称。sourceSet通常表示的是Gradle项目的某个源码集(如maintest等),而实现配置名称一般是类似于implementation的字符串(如mainImplementation)。
  2. 构建依赖项字符串

    jooqExtension.getEdition().map(e -> e.getGroupId() + ":jooq")
    .flatMap(ga -> jooqExtension.getVersion().map(v -> ga + ":" + v))
    • jooqExtension.getEdition():获取jooqExtensionEdition属性,这是一个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)。
  3. 添加依赖项

    project.getDependencies().addProvider(...);
    • project.getDependencies().addProvider:这是Gradle的一个方法,用来将动态提供的依赖项添加到特定配置中。
    • 第一个参数是依赖项要添加到的配置名称,这里是通过sourceSet.getImplementationConfigurationName()获取的。
    • 第二个参数是依赖项的坐标字符串,是通过jooqExtensionEditionVersion属性动态生成的。

依赖项的添加位置

这段代码中的依赖项是添加到插件所管理的项目中的,而不是插件自身的依赖。具体来说:

  • project.getDependencies().addProvider方法将依赖项添加到指定的项目配置中(例如implementation配置)。
  • sourceSet表示的是使用插件的项目的源码集,因此依赖项是添加到这个项目的实现配置中。

依赖项添加的总结

总结来说,这段代码通过动态获取jooqExtensionEditionVersion属性,生成依赖项的坐标字符串,并将该依赖项添加到使用该插件的项目的实现配置中。这种方式允许插件用户通过配置jooqExtension来灵活地管理他们的项目依赖,而不需要直接在构建脚本中手动添加依赖项。

Gradle Property.finalizeValueOnRead()

在Gradle中,Property接口提供了一种灵活且类型安全的方式来处理属性。finalizeValueOnRead()方法是Property接口中的一个方法,用于控制属性值的生命周期和变化。

代码解析

private final Property<String> version;
private final Property<JooqEdition> edition;
  • 这两行定义了两个私有的最终属性,分别是versionedition。它们的类型是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;
}
}

在这个示例中:

  • versionedition是两个属性,它们的值在第一次被读取时会被固定下来。
  • version.finalizeValueOnRead();edition.finalizeValueOnRead(); 确保了这两个属性的值在被第一次读取后不会再被改变。

总结

finalizeValueOnRead() 方法在属性被读取时将其值固定下来,以确保属性值在整个构建过程中的一致性和稳定性。这种机制有助于防止配置在运行时发生意外变化,确保插件或任务的行为是可预测和一致的。