Gradle之Task创建过程浅析

1,151 阅读2分钟

Gradle之Task创建过程浅析

Task创建方式:create & register

gradle中任务的创建方式有两种:

  • 直接创建该Task

  • 注册Task,即创建TaskProvider,真正使用到该Task时才创建

Task注册过程

当我们通过 project.tasks.registerTask() 注册任务的时候,实际上调用的是 TaskContainer 中的方法,其默认实现是 DefaultTaskContainer

org.gradle.api.internal.tasks.DefaultTaskContainer

private <T extends Task> TaskProvider<T> registerTask(final String name, final Class<T> type, @Nullable final Action<? super T> configurationAction, final Object... constructorArgs) {
        if (hasWithName(name)) {
            failOnDuplicateTask(name);
        }

        final TaskIdentity<T> identity = TaskIdentity.create(name, type, project);

        // 创建并返回TaskProvider
        TaskProvider<T> provider = buildOperationExecutor.call(new CallableBuildOperation<TaskProvider<T>>() {
            @Override
            public BuildOperationDescriptor.Builder description() {
                return registerDescriptor(identity);
            }

            @Override
            public TaskProvider<T> call(BuildOperationContext context) {
                TaskProvider<T> provider = Cast.uncheckedNonnullCast(
                    getInstantiator().newInstance(
                        TaskCreatingProvider.class, DefaultTaskContainer.this, identity, configurationAction, constructorArgs
                    )
                );
                addLaterInternal(provider);
                context.setResult(REGISTER_RESULT);
                return provider;
            }
        });

        if (eagerlyCreateLazyTasks) {
            provider.get();
        }

        return provider;
    }

任务注册的时候,只是创建了一个 TaskProvider 实例,只有当实际需要使用该 Task 的时候才会触发任务创建过程。

private <T extends Task> T createTask(TaskIdentity<T> identity, @Nullable Object[] constructorArgs) throws InvalidUserDataException {
        if (constructorArgs != null) {
            for (int i = 0; i < constructorArgs.length; i++) {
                if (constructorArgs[i] == null) {
                    throw new NullPointerException(String.format("Received null for %s constructor argument #%s", identity.type.getName(), i + 1));
                }
            }
        }
        // 创建Task实例
        return taskFactory.create(identity, constructorArgs);
    }

实际上,registerTask() 最后调用的也还是 createTask() 方法, createTask() 方法通过 ITaskFactory 创建Task实例。ITaskFactory 顾名思义就是创建 Task 的工厂类:

Task 创建过程

ITaskFactory 这个接口,默认有三个实现类,那么我们究竟使用的是哪一个实现类呢?事实上,这三个实现类是以责任链的方式串联在一起,分别负责处理 Task 创建的不同过程:

org.gradle.internal.service.scopes.BuildScopeServices

 protected ITaskFactory createITaskFactory(Instantiator instantiator, TaskClassInfoStore taskClassInfoStore, PropertyWalker propertyWalker) {
        return new AnnotationProcessingTaskFactory(
            instantiator,
            taskClassInfoStore,
            new PropertyAssociationTaskFactory(
                new TaskFactory(),
                propertyWalker
            ));
    }
AnnotationProcessingTaskFactory

org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory

/**
 * A {@link ITaskFactory} which determines task actions, inputs and outputs based on annotation attached to the task properties. Also provides some validation based on these annotations.
 */

如注释所说,AnnotationProcessingTaskFactory 这个类主要是负责解析 Task 类的注解,处理标识 Task 内容的注解,例如处理 @Action 注解,将改注解标识的方法封装成 Action 实例,并添加到 actionList 中

PropertyAssociationTaskFactory

org.gradle.api.internal.project.taskfactory.PropertyAssociationTaskFactory

private static class Listener implements PropertyVisitor {
        private final Task task;

        public Listener(Task task) {
            this.task = task;
        }

        @Override
        public boolean visitOutputFilePropertiesOnly() {
            return true;
        }
        
        @Override
        public void visitOutputFileProperty(String propertyName, boolean optional, PropertyValue value, OutputFilePropertyType filePropertyType) {
            // 注意:此处将task与property绑定在一起
            value.attachProducer(task);
        }
    }

PropertyAssociationTaskFactory 则是负责遍历及初始化 property,其中最重要就是 PropertyAssociationTaskFactory$Listener 这个内部类,这个内部类负责初始化 @OutputFile 注解标识的 property,也就是将当前 task 实例绑定到该 Property 中。

后续我们会讲到,这个 Property 是连接两个不同的任务的纽带,也就是生产者生产和消费者消费的 产品 。而恰恰是这个地方,将两个任务连接起来,消费者通过这个 Property 便可以获取到生产者,从而建立起 任务依赖关系

TaskFactory

org.gradle.api.internal.project.taskfactory.TaskFactory

TaskFactory 这个类才是真正负责实例化 Task 的类:

public <S extends Task> S create(final TaskIdentity<S> identity, @Nullable final Object[] constructorArgs) {
        ......
        final Class<? extends AbstractTask> implType;
        if (identity.type.isAssignableFrom(DefaultTask.class)) {
            implType = DefaultTask.class;
        } else {
            implType = identity.type.asSubclass(AbstractTask.class);
        }

        return AbstractTask.injectIntoNewInstance(project, identity, new Callable<S>() {
            @Override
            public S call() {
                try {
                    Task instance;
                    if (constructorArgs != null) {
                        // 有构造参数
                        instance = instantiationScheme.instantiator().newInstance(implType, constructorArgs);
                    } else {
                        // 无构造参数
                        instance = instantiationScheme.deserializationInstantiator().newInstance(implType, AbstractTask.class);
                    }
                    return identity.type.cast(instance);
                } catch (ObjectInstantiationException e) {
                    ......
                }
            }
        });
    }

以上任务创建实例化的过程,需要注意的是:这里并不是简简单单的实例化 implType,而是动态的生成 __implType __ 类的子类,例如 implType_DecoratedimplTypeDecorated__ 或 __implTypeInject

为什么需要这么做呢?一方面,implType 类很有可能只是抽象类,是无法直接实例化;另一方面,自动生成的装饰类也会添加一些辅助(DSL)方法:

动态生成 Task 子类的过程

DefaultInstantiationScheme$DefaultDeserializationInstantiator

org.gradle.internal.instantiation.generator.DefaultInstantiationScheme$DefaultDeserializationInstantiator

@Override
        public <T> T newInstance(Class<T> implType, Class<? super T> baseClass) {
            // TODO - The baseClass can be inferred from the implType, so attach the serialization constructor onto the GeneratedClass rather than parameterizing and caching here
            try {
                ClassGenerator.SerializationConstructor<?> constructor = constructorCache.get(implType, type -> classGenerator.generate(implType).getSerializationConstructor(baseClass));
                return implType.cast(constructor.newInstance(services, nestedGenerator));
            } catch (InvocationTargetException e) {
                throw new ObjectInstantiationException(implType, e.getCause());
            } catch (Exception e) {
                throw new ObjectInstantiationException(implType, e);
            }
        }

当我们以无参数的方式实例化 Task 的时候,即会通过 DefaultDeserializationInstantiator 实例化该Task,而 DefaultDeserializationInstantiator 则会动态的生成 Task 的子类:

AbstractClassGenerator

org.gradle.internal.instantiation.generator.AbstractClassGenerator

/**
 * Generates a subclass of the target class to mix-in some DSL behaviour.
 *
 * <ul>
 * <li>For each property, a convention mapping is applied. These properties may have a setter method.</li>
 * <li>For each property whose getter is annotated with {@code Inject}, a service instance will be injected instead. These properties may have a setter method and may be abstract.</li>
 * <li>For each mutable property as set method is generated.</li>
 * <li>For each method whose last parameter is an {@link org.gradle.api.Action}, an override is generated that accepts a {@link groovy.lang.Closure} instead.</li>
 * <li>Coercion from string to enum property is mixed in.</li>
 * <li>{@link groovy.lang.GroovyObject} and {@link DynamicObjectAware} is mixed in to the class.</li>
 * <li>An {@link ExtensionAware} implementation is added, unless {@link NonExtensible} is attached to the class.</li>
 * <li>An {@link IConventionAware} implementation is added, unless {@link NoConventionMapping} is attached to the class.</li>
 * </ul>
 */
abstract class AbstractClassGenerator implements ClassGenerator {
    ......
}

我们重点来看一下,kotlin 代码中的 “ abstract val property; ” 是最终动态生成的代码是什么?

AsmBackedClassGenerator

org.gradle.internal.instantiation.generator.AsmBackedClassGenerator

     private static class ClassBuilderImpl implements ClassGenerationVisitor {
        ......
        private String propFieldName(PropertyMetadata property) {
            return "__" + property.getName() + "__";
        }
        ......
        @Override
        public void applyReadOnlyManagedStateToGetter(PropertyMetadata property, Method getter) {
            // GENERATE public <type> <getter>() {
            //     if (<field> == null) {
            //         <field> = getFactory().newInstance(this, <display-name>, <type>, <prop-name>);
            //     }
            //     return <field>;
            // }
            ......
        } 
 
    }

从上面的代码可以看出,gradle 会为 property,动态生成一个 "_property_" 的成员变量,并通过 getFactory().newInstance(...) 初始化该变量,而 getFactory() 返回的是 ManagedObjectFactory 的实例:

ManagedObjectFactory

org.gradle.internal.instantiation.generator.ManagedObjectFactory

// Called from generated code
    public Object newInstance(GeneratedSubclass owner, @Nullable Describable ownerDisplayName, String propertyName, Class<?> type) {
        if (type.isAssignableFrom(ConfigurableFileCollection.class)) {
            return attachOwner(owner, ownerDisplayName, propertyName, getObjectFactory().fileCollection());
        }
        if (type.isAssignableFrom(ConfigurableFileTree.class)) {
            return attachOwner(owner, ownerDisplayName, propertyName, getObjectFactory().fileTree());
        }
        if (type.isAssignableFrom(DirectoryProperty.class)) {
            return attachOwner(owner, ownerDisplayName, propertyName, getObjectFactory().directoryProperty());
        }
        if (type.isAssignableFrom(RegularFileProperty.class)) {
            return attachOwner(owner, ownerDisplayName, propertyName, getObjectFactory().fileProperty());
        }
        return instantiator.newInstanceWithDisplayName(type, displayNameFor(owner, ownerDisplayName, propertyName));
    }

ManagedObjectFactory 自动根据 property 的类型,为其创建不同类型的实例,例如对于 ConfigurableFileCollection 创建的是 DefaultConfigurableFileCollection 实例;对于 DirectoryProperty 创建的是 DefaultDirectoryVar 实例等等。