Gradle Plugin 如何向特定块添加方法?

rat*_*lig 3 java groovy gradle

我想知道 Gradle 是如何实现这种机制的:向仅在该块中工作的脚本块添加特定方法。

例如,如果我想使用implementation方法,我必须apply plugin: 'java',但我只能implementationdependencies{}

mad*_*ead 5

dependencies块只是一个DependencyHandler. 默认实现是DefaultDependencyHandler. 请注意,它实现了MethodMixIn

修饰的域对象类型可以选择实现此接口以动态公开除在类型上静态声明的方法之外的方法。请注意,当类型实现此接口时,将不会使用动态 Groovy 调度来发现不透明的方法。也就是说,诸如此类的方法methodMissing()将被忽略。

所以,这个 mixin 有点像methodMissingGroovy 中的 a。每当在 Groovy 对象上调用未知方法时,如果它有methodMissing方法,就会调用它。 MethodMixIn似乎工作类似。它定义了一个方法:

MethodAccess getAdditionalMethods();
Run Code Online (Sandbox Code Playgroud)

让我们看看它是如何实现的DefaultDependencyHandler

public MethodAccess getAdditionalMethods() {
    return dynamicMethods;
}
Run Code Online (Sandbox Code Playgroud)

其中dynamicMethods初始化为:

dynamicMethods = new DynamicAddDependencyMethods(configurationContainer, new DirectDependencyAdder());
Run Code Online (Sandbox Code Playgroud)

让我们检查一下DynamicAddDependencyMethods。首先,它定义了一个hasMethod,true当存在具有给定名称的配置时返回:

public boolean hasMethod(String name, Object... arguments) {
    return arguments.length != 0 && configurationContainer.findByName(name) != null;
}
Run Code Online (Sandbox Code Playgroud)

应用的Java插件后,你configurations将有类似的对象apiimplementation等等。因此,hasMethod("api")将返回true, while hasMethod("API")false,除非您有另一个插件提供具有该名称的配置。

最后,tryInvokeMethod每当配置名称像dependencies块中的函数一样使用时,就会调用 in :

public DynamicInvokeResult tryInvokeMethod(String name, Object... arguments) {
    if (arguments.length == 0) {
        return DynamicInvokeResult.notFound();
    }
    Configuration configuration = configurationContainer.findByName(name);
    if (configuration == null) {
        return DynamicInvokeResult.notFound();
    }

    List<?> normalizedArgs = CollectionUtils.flattenCollections(arguments);
    if (normalizedArgs.size() == 2 && normalizedArgs.get(1) instanceof Closure) {
        return DynamicInvokeResult.found(dependencyAdder.add(configuration, normalizedArgs.get(0), (Closure) normalizedArgs.get(1)));
    } else if (normalizedArgs.size() == 1) {
        return DynamicInvokeResult.found(dependencyAdder.add(configuration, normalizedArgs.get(0), null));
    } else {
        for (Object arg : normalizedArgs) {
            dependencyAdder.add(configuration, arg, null);
        }
        return DynamicInvokeResult.found();
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,它只是查找命名配置并向其添加依赖项。

就是这样制作的。