Gradle源码解读(三)

  • 概述

    前面我们分析到DefaultGradleLauncher的doClassicBuildStages方法:

    private void doClassicBuildStages(Stage upTo) {
        if (this.stage == null) {
            this.instantExecution.prepareForBuildLogicExecution();
        }
    
        this.prepareSettings();
        if (upTo != DefaultGradleLauncher.Stage.LoadSettings) {
            this.prepareProjects();
            if (upTo != DefaultGradleLauncher.Stage.Configure) {
                this.prepareTaskExecution();
                if (upTo != DefaultGradleLauncher.Stage.TaskGraph) {
                    this.instantExecution.saveScheduledWork();
                    this.runWork();
                }
            }
        }
    }
    
    private final ProjectsPreparer projectsPreparer;
    private final BuildWorkExecutor buildExecuter;
    private final SettingsPreparer settingsPreparer;
    private final TaskExecutionPreparer taskExecutionPreparer;
    
    private void prepareSettings() {
        if (this.stage == null) {
              //buildListener主要是日志通知什么的辅助功能
            this.buildListener.buildStarted(this.gradle);
            this.settingsPreparer.prepareSettings(this.gradle);
            this.stage = DefaultGradleLauncher.Stage.LoadSettings;
        }
    
    }
    
    private void prepareProjects() {
        if (this.stage == DefaultGradleLauncher.Stage.LoadSettings) {
            ClassLoaderScope baseProjectClassLoaderScope = this.buildSourceBuilder.buildAndCreateClassLoader(this.gradle);
            this.gradle.setBaseProjectClassLoaderScope(baseProjectClassLoaderScope);
            this.projectsPreparer.prepareProjects(this.gradle);
            this.stage = DefaultGradleLauncher.Stage.Configure;
        }
    
    }
    
    private void prepareTaskExecution() {
        if (this.stage == DefaultGradleLauncher.Stage.Configure) {
            this.taskExecutionPreparer.prepareForTaskExecution(this.gradle);
            this.stage = DefaultGradleLauncher.Stage.TaskGraph;
        }
    
    }
    
    private void runWork() {
        if (this.stage != DefaultGradleLauncher.Stage.TaskGraph) {
            throw new IllegalStateException("Cannot execute tasks: current stage = " + this.stage);
        } else {
            List<Throwable> taskFailures = new ArrayList();
            this.buildExecuter.execute(this.gradle, taskFailures);
            if (!taskFailures.isEmpty()) {
                throw new MultipleBuildFailures(taskFailures);
            } else {
                this.stage = DefaultGradleLauncher.Stage.RunTasks;
            }
        }
    }
    

    可以看到,依次会进行到四个状态:LoadSettings、Configure、TaskGraph、RunTasks,其实最后还有一个Finished状态。

    可知的字段(IDE索引):this.gradle实现类是DefaultGradle。主要是SettingsPreparer、ProjectsPreparer、TaskExecutionPreparer、BuildWorkExecutor的实现类是什么,他们的prepareXxx方法做了什么。

    下面逐个来分析。

  • prepareSettings

    this.settingsPreparer的实现类是DefaultSettingsPreparer:

    public void prepareSettings(GradleInternal gradle) {
          //InitScriptHandler(执行init-scripts)
        this.initScriptHandler.executeScripts(gradle);
        SettingsLoader settingsLoader = gradle.getParent() != null ? this.settingsLoaderFactory.forNestedBuild() : this.settingsLoaderFactory.forTopLevelBuild();
          //以DefaultSettingsLoader为例来看
        settingsLoader.findAndLoadSettings(gradle);
    }
    
    public SettingsInternal findAndLoadSettings(GradleInternal gradle) {
        StartParameter startParameter = gradle.getStartParameter();
          //buildLayoutFactory包含了项目目录信息,这里获取setting.gradle文件的所在目录
        SettingsLocation settingsLocation = this.buildLayoutFactory.getLayoutFor(new BuildLayoutConfiguration(startParameter));
          //给System的静态字段props设置包含系统、环境、命令行参数的所有属性
        this.loadGradlePropertiesFrom(settingsLocation);
        SettingsInternal settings = this.findSettingsAndLoadIfAppropriate(gradle, startParameter, settingsLocation, gradle.getClassLoaderScope());
        ProjectSpec spec = ProjectSpecs.forStartParameter(startParameter, settings);
        if (this.useEmptySettings(spec, settings, startParameter)) {
            settings = this.createEmptySettings(gradle, startParameter, settings.getClassLoaderScope());
        }
    
        this.setDefaultProject(spec, settings);
        return settings;
    }
    
    private SettingsInternal findSettingsAndLoadIfAppropriate(GradleInternal gradle, StartParameter startParameter, SettingsLocation settingsLocation, ClassLoaderScope classLoaderScope) {
          //this.settingsProcessor是ScriptEvaluatingSettingsProcessor
        SettingsInternal settings = this.settingsProcessor.process(gradle, settingsLocation, classLoaderScope, startParameter);
        this.validate(settings);
        return settings;
    }
    
    public SettingsInternal process(GradleInternal gradle, SettingsLocation settingsLocation, ClassLoaderScope baseClassLoaderScope, StartParameter startParameter) {
        Timer settingsProcessingClock = Time.startTimer();
        Map<String, String> properties = this.gradleProperties.mergeProperties(Collections.emptyMap());
        TextResourceScriptSource settingsScript = new TextResourceScriptSource(this.textFileResourceLoader.loadFile("settings file", settingsLocation.getSettingsFile()));
        SettingsInternal settings = this.settingsFactory.createSettings(gradle, settingsLocation.getSettingsDir(), settingsScript, properties, startParameter, baseClassLoaderScope);
        gradle.getBuildListenerBroadcaster().beforeSettings(settings);
          //解析脚本
        this.applySettingsScript(settingsScript, settings);
        LOGGER.debug("Timing: Processing settings took: {}", settingsProcessingClock.getElapsed());
        return settings;
    }
    
    private void applySettingsScript(TextResourceScriptSource settingsScript, SettingsInternal settings) {
        ScriptPlugin configurer = this.configurerFactory.create(settingsScript, settings.getBuildscript(), settings.getClassLoaderScope(), settings.getBaseClassLoaderScope(), true);
        configurer.apply(settings);
    }
    

    configurer是ScriptPluginImpl:

    public void apply(Object target) {
        DefaultServiceRegistry services = new DefaultServiceRegistry(new ServiceRegistry[]{DefaultScriptPluginFactory.this.scriptServices});
        services.add(ScriptPluginFactory.class, DefaultScriptPluginFactory.this.scriptPluginFactory);
        services.add(ClassLoaderScope.class, this.baseScope);
        services.add(LoggingManagerInternal.class, (LoggingManagerInternal)DefaultScriptPluginFactory.this.loggingFactoryManager.create());
        services.add(ScriptHandler.class, this.scriptHandler);
        ScriptTarget initialPassScriptTarget = this.initialPassTarget(target);
          //createCompiler创建的是ScriptCompilerImpl
        ScriptCompiler compiler = DefaultScriptPluginFactory.this.scriptCompilerFactory.createCompiler(this.scriptSource);
        CompileOperation<?> initialOperation = DefaultScriptPluginFactory.this.compileOperationFactory.getPluginsBlockCompileOperation(initialPassScriptTarget);
          //标志着setting、project还是其他脚本
        Class<? extends BasicScript> scriptType = initialPassScriptTarget.getScriptClass();
          //得到ScriptRunnerImpl
        ScriptRunner<? extends BasicScript, ?> initialRunner = compiler.compile(scriptType, initialOperation, this.baseScope, Actions.doNothing());
          //实际上调用了其内部字段this.script的run方法,this.script是BasicScript的实现类,这里是SettingsScript,此外还有ProjectScript、InitScript等
        initialRunner.run(target, services);
          //调用this.script的getInitialPluginRequests
        PluginRequests initialPluginRequests = DefaultScriptPluginFactory.this.getInitialPluginRequests(initialRunner);
          //this.script是groovy脚本解析后生成的class,这里获取根据plugin{}等信息生成的插件类集合
        PluginRequests mergedPluginRequests = DefaultScriptPluginFactory.this.autoAppliedPluginHandler.mergeWithAutoAppliedPlugins(initialPluginRequests, target);
        PluginManagerInternal pluginManager = this.topLevelScript ? initialPassScriptTarget.getPluginManager() : null;
          //调用所有注册插件的apply方法
        DefaultScriptPluginFactory.this.pluginRequestApplicator.applyPlugins(mergedPluginRequests, this.scriptHandler, pluginManager, this.targetScope);
        ScriptTarget scriptTarget = this.secondPassTarget(target);
        scriptType = scriptTarget.getScriptClass();
        CompileOperation<BuildScriptData> operation = DefaultScriptPluginFactory.this.compileOperationFactory.getScriptCompileOperation(this.scriptSource, scriptTarget);
        ScriptRunner<? extends BasicScript, BuildScriptData> runner = compiler.compile(scriptType, operation, this.targetScope, ClosureCreationInterceptingVerifier.INSTANCE);
        if (scriptTarget.getSupportsMethodInheritance() && runner.getHasMethods()) {
            scriptTarget.attachScript(runner.getScript());
        }
    
        if (runner.getRunDoesSomething()) {
            Runnable buildScriptRunner = () -> {
                  //调用ScriptRunnerImpl内部的this.script的run方法
                runner.run(target, services);
            };
            boolean hasImperativeStatements = ((BuildScriptData)runner.getData()).getHasImperativeStatements();
            scriptTarget.addConfiguration(buildScriptRunner, !hasImperativeStatements);
        }
    }
    

    initialPassTarget方法会根据需求产生三种不同的ScriptTarget:

    private ScriptTarget initialPassTarget(Object target) {
        return this.wrap(target, true);
    }
    
    private ScriptTarget wrap(Object target, boolean isInitialPass) {
        if (target instanceof ProjectInternal && this.topLevelScript) {
            return new ProjectScriptTarget((ProjectInternal)target);
        } else if (target instanceof GradleInternal && this.topLevelScript) {
            return new InitScriptTarget((GradleInternal)target);
        } else if (target instanceof SettingsInternal && this.topLevelScript) {
            return (ScriptTarget)(isInitialPass ? new InitialPassSettingScriptTarget((SettingsInternal)target) : new SettingScriptTarget((SettingsInternal)target));
        } else {
            return new DefaultScriptTarget(target);
        }
    }
    

    getInitialPluginRequests方法如下:

    private PluginRequests getInitialPluginRequests(ScriptRunner<? extends BasicScript, ?> initialRunner) {
        if (initialRunner.getRunDoesSomething()) {
            BasicScript script = (BasicScript)initialRunner.getScript();
            if (script instanceof PluginsAwareScript) {
                return ((PluginsAwareScript)script).getPluginRequests();
            }
        }
    
        return PluginRequests.EMPTY;
    }
    

    initialRunner是ScriptRunnerImpl,它的getScript方法:

    public T getScript() {
        if (this.script == null) {
              //获取类
            Class<? extends T> scriptClass = this.compiledScript.loadClass();
              //构造类对象
            this.script = (Script)DefaultScriptRunnerFactory.this.instantiator.newInstance(scriptClass, new Object[0]);
            this.script.setScriptSource(this.source);
            this.script.setContextClassloader(this.contextClassLoader);
            DefaultScriptRunnerFactory.this.listener.onScriptClassLoaded(this.source, scriptClass);
        }
    
        return this.script;
    }
    

    scriptClass是什么?this.compiledScript是ClassesDirCompiledScript,它的loadClass方法如下:

    public Class<? extends T> loadClass() {
        if (this.scriptClass == null) {
            ...
            try {
                this.scope = this.prepareClassLoaderScope();
                ClassLoader loader = this.scope.getLocalClassLoader();
                this.scriptClass = loader.loadClass(this.source.getClassName()).asSubclass(this.scriptBaseClass);
            } ...
        }
        return this.scriptClass;
    }
    

    可以看到最终的scriptClass就是根据this.source.getClassName()来获取的,根据前面的查找,已知this.source是TextResourceScriptSource,它的getClassName方法如下:

    public String getClassName() {
        if (this.className == null) {
            this.className = this.initClassName();
        }
    
        return this.className;
    }
    
    private String initClassName() {
          //这里会获取到settings.gradle文件的URI路径信息
        URI sourceUri = this.getResource().getLocation().getURI();
        if (sourceUri != null) {
              //解析获取类名
            String path = sourceUri.toString();
            return this.classNameFromPath(path);
        } else {
            return "script_" + HashUtil.createCompactMD5(this.resource.getText());
        }
    }
    
    private String classNameFromPath(String path) {
        String name = StringUtils.substringBeforeLast(StringUtils.substringAfterLast(path, "/"), ".");
        StringBuilder className = new StringBuilder(name.length());
    
        for(int i = 0; i < name.length(); ++i) {
            char ch = name.charAt(i);
              //判断每个字母是否符合Java有效标识符规则
            className.append(Character.isJavaIdentifierPart(ch) ? ch : '_');
        }
          //判断首字母是否符合Java有效标识符首字母规则
        if (!Character.isJavaIdentifierStart(className.charAt(0))) {
            className.insert(0, '_');
        }
    
        className.setLength(Math.min(className.length(), 30));
          //对其编码
        className.append('_');
        className.append(HashUtil.createCompactMD5(path));
        return className.toString();
    }
    

    可见,最后的ClassName是一个类似“settings_X43nbjb4234aerknb”这样的东西,这样的东西自然不是一个标准的可使用的类,所以推测一定在loadClass方法中做了什么特别的解析处理,经过查找loadClass的重写方法,在GroovyClassLoader(kotlin的话应该是其他专门的ClassLoader)中发现了可能有关联的实现:

    public Class loadClass(String name, boolean lookupScriptFiles, boolean preferClassOverScript, boolean resolve) throws ClassNotFoundException, CompilationFailedException {
        ...
        URL source = this.resourceLoader.loadGroovySource(name);
        Class oldClass = cls;
        cls = null;
        cls = this.recompile(source, name, oldClass);
        ...
        return cls;
    }
    
    protected Class recompile(URL source, String className, Class oldClass) throws CompilationFailedException, IOException {
        ...
        //注意这里为什么className不再往下传递了?
        return this.parseClass(new GroovyCodeSource(new File(source.toURI()), this.sourceEncoding));
        ...
    }
    

    这里调用了parseClass方法,但是className没有往下传递,这是为什么?因为接下来就是解析settings.gradle文件了,而这个过程产生的类就和“settings”本身无关了。

    parseClass方法最终调用到了GroovyClassLoader的doParseClass方法:

    private Class doParseClass(GroovyCodeSource codeSource) {
        validate(codeSource);
        CompilationUnit unit = this.createCompilationUnit(this.config, codeSource.getCodeSource());
          ...
        SourceUnit su = null;
        File file = codeSource.getFile();
        if (file != null) {
              //将构造的SourceUnit放到CompilationUnit的this.queuedSources数组中
            su = unit.addSource(file);
        } else {
            URL url = codeSource.getURL();
            if (url != null) {
                su = unit.addSource(url);
            } else {
                su = unit.addSource(codeSource.getName(), codeSource.getScriptText());
            }
        }
          
        ClassCollector collector = this.createCollector(unit, su);
          //设置内部的classgenCallback为collector
        unit.setClassgenCallclassgenCallback为back(collector);
        ...
        //最终这个方法会触发collector的createClass方法
        unit.compile(goalPhase);
        Class answer = collector.generatedClass;
        String mainClass = su.getAST().getMainClassName();
        Iterator var9 = collector.getLoadedClasses().iterator();
    
        while(var9.hasNext()) {
            Object o = var9.next();
            Class clazz = (Class)o;
            String clazzName = clazz.getName();
            this.definePackageInternal(clazzName);
            this.setClassCacheEntry(clazz);
            if (clazzName.equals(mainClass)) {
                answer = clazz;
            }
        }
    
        return answer;
    }
    

    CompilationUnit的compile方法如下:

    public void compile(int throughPhase) throws CompilationFailedException {
          //从1开始,这里使用this.phase来控制执行的顺序,所有的SourceUnitOperation在添加时都会被添加到一个LinkedList,然后这个LinkedList会被添加到一个叫this.phaseOperations的数组,下标就是指定的phase,等到compile时会按照phase获取指定的LinkedList,然后遍历执行SourceUnitOperation的call方法
        this.gotoPhase(1);
          //从1开始,到throughPhase结束
        throughPhase = Math.min(throughPhase, 9);
        while(throughPhase >= this.phase && this.phase <= 9) {
            if (this.phase == 4) {
                this.doPhaseOperation(this.resolve);
                if (this.dequeued()) {
                    continue;
                }
            }
                  //遍历this.phaseOperations中的每一个SourceUnitOperation,执行doPhaseOperation方法
            this.processPhaseOperations(this.phase);
            ...
            if (this.progressCallback != null) {
                this.progressCallback.call(this, this.phase);
            }
    
            this.completePhase();
            this.applyToSourceUnits(this.mark);
            if (!this.dequeued()) {
                this.gotoPhase(this.phase + 1);
                if (this.phase == 7) {
                    this.sortClasses();
                }
            }
        }
    
        this.errorCollector.failIfErrors();
    }
    

    先看一下doPhaseOperation方法:

    private void doPhaseOperation(Object operation) {
        if (operation instanceof PrimaryClassNodeOperation) {
            this.applyToPrimaryClassNodes((PrimaryClassNodeOperation)operation);
        } else if (operation instanceof SourceUnitOperation) {
            this.applyToSourceUnits((SourceUnitOperation)operation);
        } else {
            this.applyToGeneratedGroovyClasses((GroovyClassOperation)operation);
        }
    }
    

    这里会针对三种不同的operation执行不同的方法,内部其实就是执行每个SourceUnitOperation的call方法。

    那this.phaseOperations中的元素怎么来的?在CompilationUnit的构造方法中会调用addPhaseOperations方法:

    private void addPhaseOperations() {
        this.addPhaseOperation((SourceUnitOperation)(new SourceUnitOperation() {
            public void call(SourceUnit source) throws CompilationFailedException {
                  //这里会执行脚本的groovy规则解析,得到一个AST对象:this.ast
                  //内部通过AntlrParserPlugin来操作
                source.parse();
            }
        }), 2);
          //this.convert中利用AST产生一个ModuleNode:this.output
        this.addPhaseOperation((SourceUnitOperation)this.convert, 3);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
                  //枚举类处理
                EnumVisitor ev = new EnumVisitor(CompilationUnit.this, source);
                ev.visitClass(classNode);
            }
        }), 3);
          //this.resolver去根据ast加载脚本中所有的类
        this.addPhaseOperation((SourceUnitOperation)this.resolve, 4);
          //写入导包、注解、包、初始化代码块等信息
        this.addPhaseOperation((PrimaryClassNodeOperation)this.staticImport, 4);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
                  //内部类信息解析
                InnerClassVisitor iv = new InnerClassVisitor(CompilationUnit.this, source);
                iv.visitClass(classNode);
            }
        }), 4);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
                if (!classNode.isSynthetic()) {
                      //类本身的继承、接口等信息解析
                    GenericsVisitor genericsVisitor = new GenericsVisitor(source);
                    genericsVisitor.visitClass(classNode);
                }
    
            }
        }), 4);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
                  //拓展特性解析
                TraitComposer.doExtendTraits(classNode, source, CompilationUnit.this);
            }
        }), 5);
          //日志或错误信息输出
        this.addPhaseOperation((SourceUnitOperation)this.compileCompleteCheck, 5);
          //类内容信息解析,内部会调用ClassCollector的call方法
        this.addPhaseOperation((PrimaryClassNodeOperation)this.classgen, 7);
          //this.output将解析好的类信息输出成class文件,放在指定位置
        this.addPhaseOperation(this.output);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {    
                  //注解信息解析
                AnnotationCollectorTransform.ClassChanger actt = new AnnotationCollectorTransform.ClassChanger();
                actt.transformClass(classNode);
            }
        }), 4);
        ASTTransformationVisitor.addPhaseOperations(this);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
                  //静态成员信息
                StaticVerifier sv = new StaticVerifier();
                sv.visitClass(classNode, source);
            }
        }), 4);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
                  //内部类成员信息
                InnerClassCompletionVisitor iv = new InnerClassCompletionVisitor(CompilationUnit.this, source);
                iv.visitClass(classNode);
            }
        }), 5);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
                  //枚举成员信息
                EnumCompletionVisitor ecv = new EnumCompletionVisitor(CompilationUnit.this, source);
                ecv.visitClass(classNode);
            }
        }), 5);
        this.addPhaseOperation((PrimaryClassNodeOperation)(new PrimaryClassNodeOperation() {
            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
                  //元数据信息
                Object callback = classNode.getNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
                if (callback instanceof PrimaryClassNodeOperation) {
                    ((PrimaryClassNodeOperation)callback).call(source, context, classNode);
                    classNode.removeNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
                }
    
            }
        }), 6);
    }
    

    按照phase的顺序依次执行,利用ASM等字节码工具,整套过程把groovy脚本转换成class文件。

  • prepareProjects

    DefaultProjectsPreparer的prepareProjects方法如下:

    public void prepareProjects(GradleInternal gradle) {
          this.maybeInformAboutIncubatingMode(gradle);
          //生成所有project的DefaultProject实例并保存起来
          this.buildLoader.load(gradle.getSettings(), gradle);
          if (gradle.getParent() == null) {
              this.buildRegistry.beforeConfigureRootBuild();
          }
          //开启所有project的configure
          if (gradle.getStartParameter().isConfigureOnDemand()) {
              this.projectConfigurer.configure(gradle.getRootProject());
          } else {
              this.projectConfigurer.configureHierarchy(gradle.getRootProject());
              (new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
          }
    
          this.modelConfigurationListener.onConfigure(gradle);
    }
    

    this.buildLoader是InstantiatingBuildLoader,它的load方法如下:

      public void load(SettingsInternal settings, GradleInternal gradle) {
          this.createProjects(gradle, settings.getRootProject());
          this.attachDefaultProject(gradle, settings.getDefaultProject());
      }
    
      private void attachDefaultProject(GradleInternal gradle, ProjectDescriptor defaultProjectDescriptor) {
          ProjectInternal rootProject = gradle.getRootProject();
          ProjectRegistry<ProjectInternal> projectRegistry = rootProject.getProjectRegistry();
          String defaultProjectPath = defaultProjectDescriptor.getPath();
          ProjectInternal defaultProject = (ProjectInternal)projectRegistry.getProject(defaultProjectPath);
          if (defaultProject == null) {
              throw new IllegalStateException("Did not find project with path " + defaultProjectPath);
          } else {
              gradle.setDefaultProject(defaultProject);
          }
      }
    
      private void createProjects(GradleInternal gradle, ProjectDescriptor rootProjectDescriptor) {
          ClassLoaderScope baseProjectClassLoaderScope = gradle.baseProjectClassLoaderScope();
          ClassLoaderScope rootProjectClassLoaderScope = baseProjectClassLoaderScope.createChild("root-project");
          ProjectInternal rootProject = this.projectFactory.createProject(gradle, rootProjectDescriptor, (ProjectInternal)null, rootProjectClassLoaderScope, baseProjectClassLoaderScope);
          gradle.setRootProject(rootProject);
          this.createChildProjectsRecursively(gradle, rootProject, rootProjectDescriptor, rootProjectClassLoaderScope, baseProjectClassLoaderScope);
      }
    
      private void createChildProjectsRecursively(GradleInternal gradle, ProjectInternal parentProject, ProjectDescriptor parentProjectDescriptor, ClassLoaderScope parentProjectClassLoaderScope, ClassLoaderScope baseProjectClassLoaderScope) {
          Iterator var6 = parentProjectDescriptor.getChildren().iterator();
    
          while(var6.hasNext()) {
              ProjectDescriptor childProjectDescriptor = (ProjectDescriptor)var6.next();
              ClassLoaderScope childProjectClassLoaderScope = parentProjectClassLoaderScope.createChild("project-" + childProjectDescriptor.getName());
              ProjectInternal childProject = this.projectFactory.createProject(gradle, childProjectDescriptor, parentProject, childProjectClassLoaderScope, baseProjectClassLoaderScope);
              this.createChildProjectsRecursively(gradle, childProject, childProjectDescriptor, childProjectClassLoaderScope, baseProjectClassLoaderScope);
          }
    
      }
    

    可见,这里会根据多项目配置从root-project开始迭代创建所有子项目的ProjectInternal对象,this.projectFactory是ProjectFactory,它的createProject方法如下:

     public ProjectInternal createProject(GradleInternal gradle, ProjectDescriptor projectDescriptor, @Nullable ProjectInternal parent, ClassLoaderScope selfClassLoaderScope, ClassLoaderScope baseClassLoaderScope) {
          Path projectPath = ((DefaultProjectDescriptor)projectDescriptor).path();
          ProjectState projectContainer = this.projectStateRegistry.stateFor(this.owner.getBuildIdentifier(), projectPath);
          File buildFile = projectDescriptor.getBuildFile();
          TextResource resource = this.textFileResourceLoader.loadFile("build file", buildFile);
          ScriptSource source = new TextResourceScriptSource(resource);
          DefaultProject project = (DefaultProject)this.instantiator.newInstance(DefaultProject.class, new Object[]{projectDescriptor.getName(), parent, projectDescriptor.getProjectDir(), buildFile, source, gradle, projectContainer, gradle.getServiceRegistryFactory(), selfClassLoaderScope, baseClassLoaderScope});
          project.beforeEvaluate((p) -> {
              NameValidator.validate(project.getName(), "project name", DefaultProjectDescriptor.INVALID_NAME_IN_INCLUDE_HINT);
          });
          if (parent != null) {
              parent.addChildProject(project);
          }
    
          this.projectRegistry.addProject(project);
          projectContainer.attachMutableModel(project);
          return project;
      }
    

    可见,对每个子项目都生成了一个DefaultProject对象,持有了对应的build.gradle脚本内容,并添加到this.projectRegistry(DefaultProjectRegistry)中。
    接下来开始执行每个project的configure,this.projectConfigurer是TaskPathProjectEvaluator,它的configureHierarchy方法如下:

      public void configureHierarchy(ProjectInternal project) {
          this.configure(project);
          Iterator var2 = project.getSubprojects().iterator();
    
          while(var2.hasNext()) {
              Project sub = (Project)var2.next();
              this.configure((ProjectInternal)sub);
          }
      }
    
      public void configure(ProjectInternal project) {
          if (this.cancellationToken.isCancellationRequested()) {
              throw new BuildCancelledException();
          } else {
              project.evaluate();
          }
      }
    

    可见,这里执行每个DefaultProject的evaluate方法:

      public DefaultProject evaluate() {
          //this.getProjectEvaluator()这里得到的是ConfigureActionsProjectEvaluator
          this.getProjectEvaluator().evaluate(this, this.state);
          return this;
      }
    

    ConfigureActionsProjectEvaluator的evaluate方法如下:

      public void evaluate(ProjectInternal project, ProjectStateInternal state) {
          Iterator var3 = this.configureActions.iterator();
    
          while(var3.hasNext()) {
              ProjectConfigureAction configureAction = (ProjectConfigureAction)var3.next();
              configureAction.execute(project);
          }
      }
    

    configureActions就是解析后的包含的各种内容项,比如BasePlugin、IdePlugin、JavaBasePlugin、ConfigAction等里面实现的匿名方法,这里会逐一执行。

  • prepareTaskExecution

    DefaultTaskExecutionPreparer的prepareForTaskExecution方法如下:

      public void prepareForTaskExecution(GradleInternal gradle) {
          this.buildConfigurationActionExecuter.select(gradle);
          TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
          taskGraph.populate();
          this.includedBuildControllers.populateTaskGraphs();
          if (gradle.getStartParameter().isConfigureOnDemand()) {
              (new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
          }
      }
    

    这里主要是将任务图中的被此次gradle执行命令include的task都加到DefaultIncludedBuildController的includedBuild(IncludedBuildState)中。

  • runWork

    到了runWork阶段,最后也会执行一系列实现自Action的一系列回调,和configure阶段类似的,只不过这里是执行而不是配置。

  • 总结

    经过一系列繁琐的过程后,settings.gradle脚本中的信息转化为了class对象,在这个对象里涵盖了project和module任务等信息,ScriptPluginImpl的apply方法最后其实就是调用了这个动态生成的class对象的run方法,内部进行解析project、tasks等的逻辑,生成项目包含逻辑、任务依赖图,后面根据这些信息执行configure阶段,最后按照任务依赖顺序执行任务。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容