You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于插件配置条件创建任务,是否必须用project.afterEvaluate?

Gradle插件:基于配置条件创建任务的正确方式

背景

我正在编写一个Gradle插件,需要根据配置动态创建数量可变的任务。以下是简化后的代码:

配置扩展类

public class TypedMaterialsExtension{
    private Property<Boolean> createTheTask;

    public TypedMaterialsExtension(Project project) {
        createTheTask = project.getObjects().property(Boolean.class);
        createTheTask.set(false);
    }

    public Property<Boolean> getCreateTheTask() {
        return createTheTask;
    }
}

项目中的配置使用

typedMaterials{
  createTheTask = true
}

插件实现代码

public class TypedMaterialsPlugin implements Plugin<Project> {
    public void apply(Project project) {

        TypedMaterialsExtension extension = project.getExtensions().create("typedMaterials", TypedMaterialsExtension.class, project);

        // 这里的beforeTask无法成功注册
        if(extension.getCreateTheTask().get()){
            project.getTasks().register("beforeTask", TypedJarMaterials.class, task -> {});
            project.getTasks().named("compileJava").configure(compileJava -> {
                compileJava.dependsOn("beforeTask");
            });
        }

        // 这里的afterTask可以成功注册
        project.afterEvaluate(p -> {
            if(extension.getCreateTheTask().get()){
                project.getTasks().register("afterTask", TypedJarMaterials.class, task -> {});
                project.getTasks().named("compileJava").configure(compileJava -> {
                    compileJava.dependsOn("afterTask");
                });
            }
        });
    }
}

实际运行时,afterTask能正常注册,但beforeTask无法被创建。

问题

我发现只有在project.afterEvaluate的Lambda中才能正确读取到用户配置的值。虽然可以把所有逻辑都放到afterEvaluate块里,但我知道这属于不良实践。那么,基于配置条件创建任务的正确做法是什么?

解决方案

问题根源

在Gradle的执行流程中,插件的apply方法会在项目配置阶段早期执行,此时用户在build.gradle中编写的typedMaterials{}配置代码还未运行,所以直接调用extension.getCreateTheTask().get()拿到的是扩展类中设置的默认值false,自然不会创建beforeTask。而afterEvaluate是在所有项目配置完成后才执行,此时能正确获取到用户设置的true。

正确实现方式

Gradle推荐利用延迟配置API和Property的响应式特性来避免直接读取配置值,从而不需要依赖afterEvaluate。

方式1:监听配置值变化

通过Property的whenTrue方法监听值的变化,当配置值变为true时,执行任务创建逻辑:

public class TypedMaterialsPlugin implements Plugin<Project> {
    public void apply(Project project) {
        TypedMaterialsExtension extension = project.getExtensions().create("typedMaterials", TypedMaterialsExtension.class, project);

        // 监听createTheTask的值变为true时的回调
        extension.getCreateTheTask().whenTrue(shouldCreate -> {
            project.getTasks().register("beforeTask", TypedJarMaterials.class, task -> {});
            project.getTasks().named("compileJava").configure(compileJava -> {
                compileJava.dependsOn("beforeTask");
            });
        });
    }
}

这种方式会在用户配置createTheTask = true后立即触发任务创建,完全符合Gradle的配置阶段执行逻辑。

方式2:利用Provider延迟绑定

如果需要更灵活的条件控制,可以使用Provider的map方法将配置值转换为任务创建逻辑,或者结合tasks.register的惰性特性:

public class TypedMaterialsPlugin implements Plugin<Project> {
    public void apply(Project project) {
        TypedMaterialsExtension extension = project.getExtensions().create("typedMaterials", TypedMaterialsExtension.class, project);
        Provider<Boolean> shouldCreateTask = extension.getCreateTheTask();

        // 注册任务,但仅当配置值为true时才实际初始化任务
        TaskProvider<TypedJarMaterials> beforeTask = project.getTasks().register("beforeTask", TypedJarMaterials.class, task -> {});
        
        // 根据配置值控制任务是否启用,以及是否添加依赖
        beforeTask.configure(task -> {
            task.setEnabled(shouldCreateTask.get());
        });

        project.getTasks().named("compileJava").configure(compileJava -> {
            // 仅当配置值为true时,添加依赖
            shouldCreateTask.map(shouldCreate -> shouldCreate ? beforeTask : null).ifPresent(compileJava::dependsOn);
        });
    }
}

这种方式下任务会被注册,但只有当配置值为true时才会启用并添加依赖,适合需要保留任务存在但控制执行的场景。

注意事项

  • 避免直接在apply阶段调用Property.get(),这会强制立即解析配置值,导致无法获取用户的后续配置。
  • 优先使用Gradle的响应式API(如whenTrue、map、ifPresent)来实现延迟逻辑,这是Gradle官方推荐的最佳实践。

内容的提问来源于stack exchange,提问作者Richard Tingle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 21:20:26