gradle源码分析之implementation依赖

作者: LSteven | 来源:发表于2020-08-04 19:51 被阅读0次

    Groovy

    dependencies {
        implementation project(':sdk')
    }
    

    groovy会做两步:

    • 解析project
    • 解析implementation

    我们先看第二步

    解析implementation

    Project.java

    /**
     * <p>Configures the dependencies for this project.
     *
     * <p>This method executes the given closure against the {@link DependencyHandler} for this project. The {@link
     * DependencyHandler} is passed to the closure as the closure's delegate.
     *
     * <h3>Examples:</h3>
     * See docs for {@link DependencyHandler}
     *
     * @param configureClosure the closure to use to configure the dependencies.
     */
    void dependencies(Closure configureClosure);
    
    
    public void dependencies(Closure configureClosure) {
        ConfigureUtil.configure(configureClosure, this.getDependencies());
    }
    

    dependenciesproject下的方法, 实际返回DefaultDependencyHandler.

    即执行DefaultDependencyHandlerimplementation方法。

    但是底下并没有这个方法,

    MethodMissing

    MethodMixIn

    public interface MethodMixIn {
        MethodAccess getAdditionalMethods();
    }
    
    this.dynamicMethods = new DynamicAddDependencyMethods(configurationContainer, new DefaultDependencyHandler.DirectDependencyAdder());
    

    MethodAccess

    public interface MethodAccess {
        boolean hasMethod(String var1, Object... var2);
    
        DynamicInvokeResult tryInvokeMethod(String var1, Object... var2);
    }
    

    动态语言常见的methodMissing功能,这里在tryInvokeMethod尝试解析方法与参数。

    class DynamicAddDependencyMethods implements MethodAccess {
    
        //name = "implementation" argument: project(sdk)
        public DynamicInvokeResult tryInvokeMethod(String name, Object... arguments) {
            //找是否有对应的configurationName
            Configuration configuration = (Configuration)this.configurationContainer.findByName(name);
            
            return DynamicInvokeResult.found(this.dependencyAdder.add(configuration, normalizedArgs.get(0), (Closure)null));
        }
    }
    
    /**
     dependencyNotation: project(:xxx)
    */
    private Dependency doAdd(Configuration configuration, Object dependencyNotation, Closure configureClosure) {
        if (dependencyNotation instanceof Configuration) {
            Configuration other = (Configuration)dependencyNotation;
            if (!this.configurationContainer.contains(other)) {
                throw new UnsupportedOperationException("Currently you can only declare dependencies on configurations from the same project.");
            } else {
                configuration.extendsFrom(new Configuration[]{other});
                return null;
            }
        } else {
            Dependency dependency = this.create(dependencyNotation, configureClosure);
            configuration.getDependencies().add(dependency);
            return dependency;
        }
    }
    
    public Dependency create(Object dependencyNotation, Closure configureClosure) {
        Dependency dependency = this.dependencyFactory.createDependency(dependencyNotation);
        return (Dependency)ConfigureUtil.configure(configureClosure, dependency);
    }
    
    //DependencyProjectNotationConverter
    public Dependency createDependency(Object dependencyNotation) {
        Dependency dependency = (Dependency)this.dependencyNotationParser.parseNotation(dependencyNotation);
        this.injectServices(dependency);
        return dependency; //DefaultProjectDependency
    }
    

    DependencyProjectNotationConverter 将 Project 转换为 ProjectDependency,对应 implementation project(":applemodule") 这样的情形

    所以主要就两步:

    1. Dependency dependency = this.create(dependencyNotation, configureClosure);
    2. configuration.getDependencies().add(dependency);
    

    解析project

    一样进入tryInvokeMethod,但是:

    Configuration configuration = (Configuration)this.configurationContainer.findByName(name);
    

    DynamicAddDependencyMethods是没有projectconfiguration:

    于是进入DefaultProjectproject方法

    public class DefaultProject {
        
        public ProjectInternal project(String path) {
            ProjectInternal project = this.findProject(path);
            if (project == null) {
                throw new UnknownProjectException(String.format("Project with path '%s' could not be found in %s.", path, this));
            } else {
                return project;
            }
        }
    }
    

    问题

    为什么能进入DefaultProjectproject方法? 因为回到parent去解析?

    ktx

    dependencies {
        implementation(project(":sdkapi"))
    }
    

    ProjectExtensions.kt

    fun Project.dependencies(configuration: DependencyHandlerScope.() -> Unit) =
        DependencyHandlerScope.of(dependencies).configuration()
        
    companion object {
        fun of(dependencies: DependencyHandler): DependencyHandlerScope =
            DependencyHandlerScope(dependencies)
    }
    

    解析project

    DependencyHandlerExtensions.kt

    fun DependencyHandler.project(
        path: String,
        configuration: String? = null
    ): ProjectDependency =
    
        uncheckedCast(
            project(
                if (configuration != null) mapOf("path" to path, "configuration" to configuration)
                else mapOf("path" to path)))
    
    override fun project(notation: Map<String, *>): Dependency =
        delegate.project(notation)
    

    最后走到DependencyHandler.project(map)方法 -> (delegate)

    public Dependency project(Map<String, ?> notation) {
        return this.dependencyFactory.createProjectDependencyFromMap(this.projectFinder, notation);
    }
    

    怪不得一直不知道这个方法是用来干啥的

    project(map)
    public ProjectDependency createFromMap(ProjectFinder projectFinder, Map<? extends String, ?> map) {
        return (ProjectDependency)NotationParserBuilder.toType(ProjectDependency.class).converter(new ProjectDependencyFactory.ProjectDependencyMapNotationConverter(projectFinder, this.factory)).toComposite().parseNotation(map);
    }
    

    最后其实就是进入:

    DefaultProjectDependencyFactory

    public ProjectDependency create(ProjectInternal project, String configuration) {
        DefaultProjectDependency projectDependency = (DefaultProjectDependency)this.instantiator.newInstance(DefaultProjectDependency.class, new Object[]{project, configuration, this.projectAccessListener, this.buildProjectDependencies});
        projectDependency.setAttributesFactory(this.attributesFactory);
        projectDependency.setCapabilityNotationParser(this.capabilityNotationParser);
        return projectDependency;
    }
    

    先通过 projectFinder 找到相应的 Project,然后通过 factory 创建 ProjectDependency

    解析implementation

    val implementation by configurations

    operator fun Configuration.invoke(dependencyNotation: Any): Dependency? =
        add(name, dependencyNotation)
    

    DefaultDependencyHandler.java

    public Dependency add(String configurationName, Object dependencyNotation) {
        return this.add(configurationName, dependencyNotation, (Closure)null);
    }
    

    问题

    val implementation by configurations咋实现的,还没看懂

    参考资料

    https://henleylee.github.io/posts/2019/5fe63be9.html#toc-heading-5
    https://www.jianshu.com/p/0e04186a6aca

    相关文章

      网友评论

        本文标题:gradle源码分析之implementation依赖

        本文链接:https://www.haomeiwen.com/subject/pivprktx.html