Gradle 和插件扩展关闭的执行顺序

Gradle and plugin extension closure order of execution

我有 3 个插件 'A'、'B' 和 'C'。插件 'A' 包括插件 'B' 以及:

project.getPlugins().apply(B.class);

插件 'B' 包括插件 'C' 以及:

project.getPlugins().apply(C.class);

总而言之,依赖关系是:A > B > C

插件 'A' 有一个自定义任务 'T_A' 和一个自定义扩展 'E_A'。插件 'C' 具有自定义扩展名 'E_C'。

当我使用以下 build.gradle 并执行 gradlew T_A 时,一切都按预期工作,这意味着属性是在 T_A 执行之前设置的:

plugins {
  id 'A'
}

E_A {
  prop_a = 'hello'
}

E_C {
  prop_c = 'world'
}

但是,具有以下 build.gradle:

plugins {
  id 'A'
}

E_C {
  prop_c = 'world'
}

E_A {
  prop_a = 'hello'
}

... 那么,prop_a 不会在任务执行前被设置。

我卡住了,真的不明白为什么可能是错的。

build.gradle 文件中扩展的关闭顺序重要吗?

在配置阶段,当您的应用函数被调用时,一些值不能保证被设置。所以顺序确实很重要,但依赖它是一种不好的做法。复杂的扩展,例如 NamedDomainObjectContainer 总是延迟配置。

首先你可以使用Property in your tasks, their values are set once they're required. This is the preferred way because it minimizes task configuration, but it can get very confusing, a guide showing how to use properties: Lazy Configuration: connecting properties together虽然它使用Groovy,但应该很容易翻译成Java。

还有一个解决方案,就是添加一个post评估监听器。一旦配置了所有插件和扩展,它就会被调用,但如果多个插件正在配置相同的任务,这可能会变得混乱。请参阅此线程讨论 project afterEvaluate usage。在旁注中,一些官方 Gradle 插件仍然按值配置任务。

class PluginA implements Plugin<Project> {
    ExtensionA a;
    public void apply(Project project) {
        a = project.getExtension().create("E_A", ExtensionA.class);
        project.getTasks().register("T_A");   //prop_a may not be set here
        project.getTasks().findByName("T_A").doLast(t -> System.out.println(a.prop_a));
        project.afterEvaluate(p -> 
            //prop_a will be set here
            p.getTasks().findByName("T_A").doLast(t -> System.out.println(a.prop_a));
        );
    }
}

显然你可以使它更干净。

我建议您与听众互动,以更好地了解 Gradle 生命周期。