Gradle 源碼分析(三)

1. 寫在前面

Gradle源碼分析(二)一文中,我們分析了Gradle構(gòu)建流程的 LoadSettings 階段,這里將分析 Configure 階段(gradle 源碼版本為 5.6.4)。

2. Configure

2.1 整體實(shí)現(xiàn)

這里我整理了 Configure 階段的一些主要操作,并繪制了調(diào)用鏈的時(shí)序圖。如果對(duì)源碼不感興趣的同學(xué)只需要看這一部分的內(nèi)容即可。

2.1.1 時(shí)序圖

Configure時(shí)序圖.png

2.1.2 主要操作

Configure 階段 Gradle 主要做了下面這些事情瞻凤。

  1. 創(chuàng)建 root project 和 sub project,它們都是 DefaultProject 對(duì)象世杀;
  2. 調(diào)用 BuildListenerprojectsLoaded()阀参;
  3. 開始配置 root project,調(diào)用 ProjectEvaluationListenerbeforeEvaluate()瞻坝,apply 默認(rèn)插件蛛壳,編譯執(zhí)行 build.gradle 文件,調(diào)用 ProjectEvaluationListenerafterEvaluate()所刀;
  4. 遍歷 sub project衙荐,重復(fù) 3 中配置 root project 的過程;
  5. 調(diào)用 BuildListenerprojectEvaluated()浮创。

2.2 源碼分析

2.2.1 創(chuàng)建 Root Project 和 Sub Project

Configure 過程是發(fā)生在 DefaultGradleLauncherprepareProjects() 中忧吟,先來看看它的源碼。

// DefaultGradleLauncher.java
private void prepareProjects() {
    if (stage == Stage.LoadSettings) {
        // 配置 projects
        projectsPreparer.prepareProjects(gradle);
        // 將狀態(tài)設(shè)置為 Configure
        stage = Stage.Configure;
    }
}

這里的 projectsPreparer 是通過反射調(diào)用的 BuildScopeServicescreateBuildConfigurer()斩披。

// BuildScopeServices.java
protected ProjectsPreparer createBuildConfigurer(ProjectConfigurer projectConfigurer, BuildStateRegistry buildStateRegistry, BuildLoader buildLoader, ListenerManager listenerManager, BuildOperationExecutor buildOperationExecutor) {
    ModelConfigurationListener modelConfigurationListener = listenerManager.getBroadcaster(ModelConfigurationListener.class);
    return new BuildOperatingFiringProjectsPreparer(
        new DefaultProjectsPreparer(
            projectConfigurer,
            buildStateRegistry,
            buildLoader,
            modelConfigurationListener,
            buildOperationExecutor),
        buildOperationExecutor);
}

BuildOperatingFiringProjectsPreparer 對(duì)象溜族,并在構(gòu)造器中傳入了 DefaultProjectsPreparer 的對(duì)象。毫無疑問垦沉,BuildOperatingFiringProjectsPreparerprepareProjects() 最后會(huì)調(diào)用到 DefaultProjectsPreparerprepareProjects()煌抒,所以直接看 DefaultProjectsPreparerprepareProjects()

// DefaultProjectsPreparer.java
public void prepareProjects(GradleInternal gradle) {
    // ...
    buildLoader.load(gradle.getSettings(), gradle);
    // ...
}

這里的 buildLoader 是通過反射調(diào)用的 BuildScoeServicescreateBuildLoader()乡话。

// BuildScoeServices.java
protected BuildLoader createBuildLoader(IGradlePropertiesLoader propertiesLoader, IProjectFactory projectFactory, BuildOperationExecutor buildOperationExecutor) {
    return new NotifyingBuildLoader(
        new ProjectPropertySettingBuildLoader(
            propertiesLoader,
            new InstantiatingBuildLoader(
                projectFactory
            )
        ),
        buildOperationExecutor
    );
}

來看看 NotifyingBuildLoaderload()摧玫。

// NotifyingBuildLoader.java
public void load(final SettingsInternal settings, final GradleInternal gradle) {
    buildOperationExecutor.call(new CallableBuildOperation<Void>() {

        @Override
        public Void call(BuildOperationContext context) {
            // 1. 調(diào)用 ProjectPropertySettingBuildLoader 的 load()
            buildLoader.load(settings, gradle);
        }
    });
    buildOperationExecutor.run(new RunnableBuildOperation() {
        @Override
        public void run(BuildOperationContext context) {
            // 2. load()走完后耳奕,會(huì)執(zhí)行 BuildListener 的 projectesLoaded()绑青,記住這里诬像,后面會(huì)提到。
            gradle.getBuildListenerBroadcaster().projectsLoaded(gradle);
        }
    });
}

這里調(diào)用了 ProjectPropertySettingBuildLoaderload()闸婴。

// ProjectPropertySettingBuildLoader.java
public void load(SettingsInternal settings, GradleInternal gradle) {
    // 1. 調(diào)用 InstantiatingBuildLoader 的 load()
    buildLoader.load(settings, gradle);
    // 2. 解析 project 目錄下的 gradle.properties 配置的屬性坏挠,簡單了解一下
    setProjectProperties(gradle.getRootProject(), new CachingPropertyApplicator());
}

這里調(diào)用了 InstantiatingBuildLoaderload()

// InstantiatingBuildLoader.java
public void load(SettingsInternal settings, GradleInternal gradle) {
    load(settings.getRootProject(), settings.getDefaultProject(), gradle, settings.getRootClassLoaderScope());
}

private void load(ProjectDescriptor rootProjectDescriptor, ProjectDescriptor defaultProject, GradleInternal gradle, ClassLoaderScope buildRootClassLoaderScope) {
    createProjects(rootProjectDescriptor, gradle, buildRootClassLoaderScope);
    attachDefaultProject(defaultProject, gradle);
}

private void attachDefaultProject(ProjectDescriptor defaultProject, GradleInternal gradle) {
    gradle.setDefaultProject(gradle.getRootProject().getProjectRegistry().getProject(defaultProject.getPath()));
}

private void createProjects(ProjectDescriptor rootProjectDescriptor, GradleInternal gradle, ClassLoaderScope buildRootClassLoaderScope) {
    // 1. 配置 root project
    ProjectInternal rootProject = projectFactory.createProject(rootProjectDescriptor, null, gradle, buildRootClassLoaderScope.createChild("root-project"), buildRootClassLoaderScope);
    // 設(shè)置 root project
    gradle.setRootProject(rootProject);
    // 調(diào)用 addProjects() 遍歷 sub project邪乍,創(chuàng)建 sub project
    addProjects(rootProject, rootProjectDescriptor, gradle, buildRootClassLoaderScope);
}

private void addProjects(ProjectInternal parent, ProjectDescriptor parentProjectDescriptor, GradleInternal gradle, ClassLoaderScope buildRootClassLoaderScope) {
    // 遍歷 sub project降狠,創(chuàng)建 sub project 
    for (ProjectDescriptor childProjectDescriptor : parentProjectDescriptor.getChildren()) {
        ProjectInternal childProject = projectFactory.createProject(childProjectDescriptor, parent, gradle, parent.getClassLoaderScope().createChild("project-" + childProjectDescriptor.getName()), buildRootClassLoaderScope);
        addProjects(childProject, childProjectDescriptor, gradle, buildRootClassLoaderScope);
    }
}

可以看到,這里主要是通過的 projectFactorycreateProject() 來創(chuàng)建 Project 對(duì)象的庇楞;而 projectFactory 是通過反射調(diào)用的 BuildScopeServicescreateProjectFactory() 榜配。

// BuildScopeServices.java
protected IProjectFactory createProjectFactory(Instantiator instantiator, ProjectRegistry<ProjectInternal> projectRegistry) {
    return new ProjectFactory(instantiator, projectRegistry);
}

ProjectFactory 對(duì)象,來看看其 createProject() 做了什么事情吕晌。

// ProjectFactory.java
public DefaultProject createProject(ProjectDescriptor projectDescriptor, ProjectInternal parent, GradleInternal gradle, ClassLoaderScope selfClassLoaderScope, ClassLoaderScope baseClassLoaderScope) {
    // 獲取到 build.gradle 
    File buildFile = projectDescriptor.getBuildFile();
    // 加載 build.gradle 
    TextResource resource = resourceLoader.loadFile("build file", buildFile);
    ScriptSource source = new TextResourceScriptSource(resource);
    // 創(chuàng)建 DefaultProject 對(duì)象
    DefaultProject project = instantiator.newInstance(DefaultProject.class,
            projectDescriptor.getName(),
            parent,
            projectDescriptor.getProjectDir(),
            buildFile,
            source,
            gradle,
            gradle.getServiceRegistryFactory(),
            selfClassLoaderScope,
            baseClassLoaderScope
    );
    // ...
    if (parent != null) {
        // sub project 添加到其 parent 里面
        parent.addChildProject(project);
    }
    // 注冊(cè) project
    projectRegistry.addProject(project);

    return project;
}

這里會(huì)創(chuàng)建 project 對(duì)象蛋褥,然后注冊(cè) project。

2.2.2 調(diào)用 BuildListener 的 projectsLoaded()

創(chuàng)建完 root project 和 sub project 后睛驳,思緒該回到之前提到過的 NotifyingBuildLoaderload() 了烙心。

// NotifyingBuildLoader.java
public void load(final SettingsInternal settings, final GradleInternal gradle) {
    buildOperationExecutor.call(new CallableBuildOperation<Void>() {
        @Override
        public BuildOperationDescriptor.Builder description() {
        @Override
        public Void call(BuildOperationContext context) {
            // 這里往下走的是前面創(chuàng)建 root project 和 sub project 的過程
            buildLoader.load(settings, gradle);
            return null
        }
    });
    buildOperationExecutor.run(new RunnableBuildOperation() {
        @Override
        public void run(BuildOperationContext context) {
            // 走完 load() 后,回調(diào)用 BuildListener 的 projectsLoaded()
            gradle.getBuildListenerBroadcaster().projectsLoaded(gradle);
        }
    });
}

可以看到在 NotifyingBuildLoaderload() 里面在走完 load() 流程后乏沸,會(huì)執(zhí)行 BuildListenerprojectsLoaded()淫茵。

2.2.3 配置 Project

看完 load() 過程,該回到 DefaultProjectPreparerprepareProjects() 繼續(xù)往下看了蹬跃。

// DefaultProjectPreparer.java
public void prepareProjects(GradleInternal gradle) {
    maybeInformAboutIncubatingMode(gradle);

    buildLoader.load(gradle.getSettings(), gradle);
    // ...
    // 如果設(shè)置了參數(shù) --configure-on-demand 進(jìn)行按需構(gòu)建匙瘪,則只會(huì)配置 root project 和 tasks 需要的 projects
    if (gradle.getStartParameter().isConfigureOnDemand()) {
        projectConfigurer.configure(gradle.getRootProject());
    } else {
        // 如果沒有設(shè)置按需配置,則默認(rèn)會(huì)構(gòu)建所有的 projects
        projectConfigurer.configureHierarchy(gradle.getRootProject());
        // 這里記一下蝶缀,也是調(diào)用生命周期方法
        new ProjectsEvaluatedNotifier(buildOperationExecutor).notify(gradle);
    }
}

可以看到在 load() 之后辆苔,會(huì)判斷是否有 --configure-on-demand 參數(shù)配置,如果配置了這個(gè)參數(shù)扼劈,gradle 會(huì)進(jìn)行按需配置(只會(huì)構(gòu)建 root project 和 tasks 需要的 projects)驻啤;如果沒有配置,則默認(rèn)會(huì)構(gòu)建所有的 projects荐吵,它是包含 root projects 的配置過程的骑冗,所以這里看 configureHierarchy() 即可。projectConfigurer 是通過反射調(diào)用的 BuildScopeServicescreateProjectConfigurer()先煎。

// BuildScopeServices.java
protected ProjectConfigurer createProjectConfigurer(BuildCancellationToken cancellationToken) {
    return new TaskPathProjectEvaluator(cancellationToken);
}

TaskPathProjectEvaluator 對(duì)象贼涩,來看看其 configureHierarchy()

// TaskPathProjectEvaluator.java
public void configure(ProjectInternal project) {
    if (cancellationToken.isCancellationRequested()) {
        throw new BuildCancelledException();
    }
    project.evaluate();
}

@Override
public void configureHierarchy(ProjectInternal project) {
    // 1. 先配置 root project薯蝎,這個(gè)和 --configure-on-demand 是一樣的
    configure(project);
    // 2. 然后遍歷 sub project遥倦,配置 sub project
    for (Project sub : project.getSubprojects()) {
        configure((ProjectInternal) sub);
    }
}

可以看到 configureHierarchy() 會(huì)先走 --configure-on-demand 的配置過程,先配置 root project, 然后再配置所有的 sub project袒哥。這里的 project 即前面創(chuàng)建的 DefaultProject缩筛,來看看其 evaluate()

// DefaultProject.java
public DefaultProject evaluate() {
    getProjectEvaluator().evaluate(this, state);
    return this;
}

public ProjectEvaluator getProjectEvaluator() {
    if (projectEvaluator == null) {
        projectEvaluator = services.get(ProjectEvaluator.class);
    }
    return projectEvaluator;
}

這里的 projectEvaluator 是通過反射調(diào)用的 BuildScopeServicescreateProjectEvaluator()堡称。

// BuildScopeServices.java
protected ProjectEvaluator createProjectEvaluator(BuildOperationExecutor buildOperationExecutor, CachingServiceLocator cachingServiceLocator, ScriptPluginFactory scriptPluginFactory) {
    ConfigureActionsProjectEvaluator withActionsEvaluator = new ConfigureActionsProjectEvaluator(
        // 這里需要注意一下瞎抛,一般project都會(huì)有默認(rèn)的任務(wù),其實(shí)就是這個(gè)類在作怪却紧,它里面執(zhí)行的時(shí)候桐臊,會(huì)給project apply 默認(rèn)的插件,然后插件里面會(huì)創(chuàng)建任務(wù)晓殊,所以每個(gè)project 才會(huì)有一些默認(rèn)的任務(wù)
        PluginsProjectConfigureActions.from(cachingServiceLocator),
        // 這里是解析執(zhí)行 build.gradle的地方
        new BuildScriptProcessor(scriptPluginFactory),
        new DelayedConfigurationActions()
    );
    return new LifecycleProjectEvaluator(buildOperationExecutor, withActionsEvaluator);
}

需要注意一下断凶,這里在創(chuàng)建 ConfigureActionsProjectEvaluator 的時(shí)候傳入了 PluginsProjectConfigureActions.from() ,這個(gè)東西有點(diǎn)意思滴嘞巫俺,來看看它做了什么懒浮。

// PluginsProjectConfigureActions.java
public static ProjectConfigureAction from(ServiceLocator serviceLocator) {
    return of(ProjectConfigureAction.class, serviceLocator);
}

public static <T extends Action<ProjectInternal>> ProjectConfigureAction of(Class<T> serviceType,
                                                                            ServiceLocator serviceLocator) {
    return new PluginsProjectConfigureActions(
        ImmutableList.<Action<ProjectInternal>>copyOf(
            serviceLocator.getAll(serviceType)));
}

這里的 serviceLocator 是通過反射調(diào)用的 GlobalScopeServicescreatePluginsServiceLocator()

// GlobalScopeServices.java
CachingServiceLocator createPluginsServiceLocator(ClassLoaderRegistry registry) {
    return CachingServiceLocator.of(
        new DefaultServiceLocator(registry.getPluginsClassLoader())
    );
}

直接看 DefaultServiceLocatorgetAll() 识藤。

// DefaultServiceLocator.java
public <T> List<T> getAll(Class<T> serviceType) throws UnknownServiceException {
    List<ServiceFactory<T>> factories = findFactoriesForServiceType(serviceType);
    ArrayList<T> services = new ArrayList<T>();
    for (ServiceFactory<T> factory : factories) {
        services.add(factory.create());
    }
    return services;
}

private <T> List<ServiceFactory<T>> findFactoriesForServiceType(Class<T> serviceType) {
    return factoriesFor(serviceType, implementationsOf(serviceType));
}

public <T> List<Class<? extends T>> implementationsOf(Class<T> serviceType) {
    try {
        return findServiceImplementations(serviceType);
    } catch (ServiceLookupException e) {
        throw e;
    } catch (Exception e) {
        throw new ServiceLookupException(String.format("Could not determine implementation classes for service '%s'.", serviceType.getName()), e);
    }
}
private <T> List<Class<? extends T>> findServiceImplementations(Class<T> serviceType) throws IOException {
    String resourceName = "META-INF/services/" + serviceType.getName();
    Set<String> implementationClassNames = new HashSet<String>();
    List<Class<? extends T>> implementations = new ArrayList<Class<? extends T>>();
    for (ClassLoader classLoader : classLoaders) {
        Enumeration<URL> resources = classLoader.getResources(resourceName);
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            List<String> implementationClassNamesFromResource;
            try {
                implementationClassNamesFromResource = extractImplementationClassNames(resource);
                if (implementationClassNamesFromResource.isEmpty()) {
                    throw new RuntimeException(String.format("No implementation class for service '%s' specified.", serviceType.getName()));
                }
            } catch (Throwable e) {
                throw new ServiceLookupException(String.format("Could not determine implementation class for service '%s' specified in resource '%s'.", serviceType.getName(), resource), e);
            }

            for (String implementationClassName : implementationClassNamesFromResource) {
                if (implementationClassNames.add(implementationClassName)) {
                    try {
                        Class<?> implClass = classLoader.loadClass(implementationClassName);
                        if (!serviceType.isAssignableFrom(implClass)) {
                            throw new RuntimeException(String.format("Implementation class '%s' is not assignable to service class '%s'.", implementationClassName, serviceType.getName()));
                        }
                        implementations.add(implClass.asSubclass(serviceType));
                    } catch (Throwable e) {
                        throw new ServiceLookupException(String.format("Could not load implementation class '%s' for service '%s' specified in resource '%s'.", implementationClassName, serviceType.getName(), resource), e);
                    }
                }
            }
        }
    }
    return implementations;
}

這個(gè)過程有沒有一點(diǎn)點(diǎn)的熟悉砚著,不就是我們?cè)?Gradle 源碼分析(一) 里面分析 PluginServiceRegistry 的注冊(cè)流程一樣的嗎,只不過那邊是傳入的 PluginServiceRegistry.class痴昧,這里傳入的是 ProjectConfigureAction.class稽穆,所以實(shí)際上這個(gè)流程是在找 META-INF/services/org.gradle.configuration.project.ProjectConfigureAction 文件下配置的 ProjectConfigureAction

ProjectConfigureAction.png

這里有三個(gè)比較重要的 ProjectConfigureAction赶撰。

  • BuildInitAutoApplyAction
  • WrapperPluginAutoApplyAction
  • HelpTasksAutoApplyAction

一個(gè)一個(gè)來看舌镶,它們究竟做了什么。

2.2.3.1 BuildInitAutoApplyAction

先來看看 BuildInitAutoApplyAction 的源碼豪娜。

// BuildInitAutoApplyAction.java
public class BuildInitAutoApplyAction implements ProjectConfigureAction {

    @Override
    public void execute(final ProjectInternal project) {
        project.getPluginManager().apply("org.gradle.build-init");
    }

}

這里給 project 添加了插件 org.gradle.build-init餐胀,如果你寫過 gradle 插件,那么一定清楚注冊(cè)插件的地方是在 META-INF/gradle-plugins 下面瘤载。

org.gradle.build-init.png

它對(duì)應(yīng)的是 BuildInitPlugin 類否灾,來看看它的源碼。

// BuildInitPlugin.java
public class BuildInitPlugin implements Plugin<Project> {
    @Override
    public void apply(final Project project) {
        // 如果是 root project鸣奔,注冊(cè) init task
        if (project.getParent() == null) {
            project.getTasks().register("init", InitBuild.class, new Action<InitBuild>() {
                @Override
                public void execute(InitBuild initBuild) {
                    initBuild.setGroup("Build Setup");
                    initBuild.setDescription("Initializes a new Gradle build.");

                    initBuild.onlyIf(new Spec<Task>() {
                        @Override
                        public boolean isSatisfiedBy(Task element) {
                            Object skippedMsg = reasonToSkip(project);
                            if (skippedMsg != null) {
                                project.getLogger().warn((String) skippedMsg);
                                return false;
                            }

                            return true;
                        }
                    });

                    initBuild.dependsOn(new Callable<String>() {
                        @Override
                        public String call() throws Exception {
                            if (reasonToSkip(project) == null) {
                                return "wrapper";
                            } else {
                                return null;
                            }
                        }
                    });
                }
            });
        }
    }
}

這個(gè)插件會(huì)給 root project 注冊(cè) init Task墨技。

2.2.3.2 WrapperPluginAutoApplyAction

來看看 WrapperPluginAutoApplyAction 的源碼。

public class WrapperPluginAutoApplyAction implements ProjectConfigureAction {
    @Override
    public void execute(ProjectInternal project) {
        project.getPluginManager().apply("org.gradle.wrapper");
    }
}

可以看到挎狸,它給 project 添加了插件 org.gradle.wrapper扣汪,同樣的在 META-INF/gradle-plugins 下搜索這個(gè)插件的注冊(cè)文件。

org.gradle.wrapper.png

它對(duì)應(yīng)的是 WrapperPlugin锨匆,來看看其源碼崭别。

// WrapperPlugin.java
public class WrapperPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        // 給root project 注冊(cè) wrapper task
        if (project.getParent() == null) {
            project.getTasks().register("wrapper", Wrapper.class, new Action<Wrapper>() {
                @Override
                public void execute(Wrapper wrapper) {
                    wrapper.setGroup("Build Setup");
                    wrapper.setDescription("Generates Gradle wrapper files.");
                }
            });
        }
    }
}

可以看到,這里給 root project 注冊(cè) wrapper task。

2.2.3.3 HelpTasksAutoApplyAction

最后來看看 HelpTasksAutoApplyAction 的源碼茅主。

// HelpTasksAutoApplyAction.java
public class HelpTasksAutoApplyAction implements ProjectConfigureAction {
    @Override
    public void execute(ProjectInternal project) {
        project.getPluginManager().apply("org.gradle.help-tasks");
    }
}

這里給 project 注冊(cè)了插件 org.gradle.help-tasks舞痰,同樣在 META-INF/gradle-plugins 下搜索這個(gè)插件的注冊(cè)文件。


org.gradle.help-tasks.png

它對(duì)應(yīng)的是 HelpTasksPlugin 暗膜,來看看其源碼。

// HelpTasksPlugin.java
    public void apply(final ProjectInternal project) {
        final TaskContainerInternal tasks = project.getTasks();

        // static classes are used for the actions to avoid implicitly dragging project/tasks into the model registry
        String projectName = project.toString();
        // 注冊(cè) help task
        tasks.register(ProjectInternal.HELP_TASK, Help.class, new HelpAction());
        // 注冊(cè) projects task
        tasks.register(ProjectInternal.PROJECTS_TASK, ProjectReportTask.class, new ProjectReportTaskAction(projectName));
        // 注冊(cè) tasks task
        tasks.register(ProjectInternal.TASKS_TASK, TaskReportTask.class, new TaskReportTaskAction(projectName, project.getChildProjects().isEmpty()));
        // 注冊(cè) properties task
        tasks.register(PROPERTIES_TASK, PropertyReportTask.class, new PropertyReportTaskAction(projectName));
        // 注冊(cè) dependencyInsight task
        tasks.register(DEPENDENCY_INSIGHT_TASK, DependencyInsightReportTask.class, new DependencyInsightReportTaskAction(projectName));
        // 注冊(cè) dependencies task
        tasks.register(DEPENDENCIES_TASK, DependencyReportTask.class, new DependencyReportTaskAction(projectName));
        // 注冊(cè) buildEnvironment task
        tasks.register(BuildEnvironmentReportTask.TASK_NAME, BuildEnvironmentReportTask.class, new BuildEnvironmentReportTaskAction(projectName));
        // 注冊(cè) components task
        tasks.register(COMPONENTS_TASK, ComponentReport.class, new ComponentReportAction(projectName));
        // 注冊(cè) model task
        tasks.register(MODEL_TASK, ModelReport.class, new ModelReportAction(projectName));
        // 注冊(cè) dependentComponents task
        tasks.register(DEPENDENT_COMPONENTS_TASK, DependentComponentsReport.class, new DependentComponentsReportAction(projectName));
    }

可以看到這里給所有的 project 注冊(cè)了許多任務(wù)鞭衩,這也是經(jīng)常說的 project 會(huì)有一些默認(rèn)任務(wù)学搜,它就是通過這個(gè)插件進(jìn)行注冊(cè)的。

經(jīng)過這個(gè)小插曲论衍,思緒該回到 BuildScopeServicecreateProjectEvaluator() 了瑞佩。

// BuildScopeService.java
protected ProjectEvaluator createProjectEvaluator(BuildOperationExecutor buildOperationExecutor, CachingServiceLocator cachingServiceLocator, ScriptPluginFactory scriptPluginFactory) {
    ConfigureActionsProjectEvaluator withActionsEvaluator = new ConfigureActionsProjectEvaluator(
        PluginsProjectConfigureActions.from(cachingServiceLocator),
        new BuildScriptProcessor(scriptPluginFactory),
        new DelayedConfigurationActions()
    );
    return new LifecycleProjectEvaluator(buildOperationExecutor, withActionsEvaluator);
}

來看看 LifecycleProjectEvaluatorevaluate()

// LifecycleProjectEvaluator.java
public void evaluate(final ProjectInternal project, final ProjectStateInternal state) {
    if (state.isUnconfigured()) {
        buildOperationExecutor.run(new EvaluateProject(project, state));
    }
}

// EvaluateProject (內(nèi)部類)
public void run(final BuildOperationContext context) {
    project.getMutationState().withMutableState(new Runnable() {
        @Override
        public void run() {
            try {
                // 1. 將 project 狀態(tài)設(shè)置為 IN_BEFORE_EVALUATE
                state.toBeforeEvaluate();
                // 2. 調(diào)用 ProjectEvaluationListener 的 beforeEvaluate()
                buildOperationExecutor.run(new NotifyBeforeEvaluate(project, state));

                if (!state.hasFailure()) {
                    // 3. 將 project 的狀態(tài)設(shè)置為 IN_EVALUATE
                    state.toEvaluate();
                    try {
                        // 4. 調(diào)用 ConfigureActionsProjectEvaluator 的 evaluate()
                        delegate.evaluate(project, state);
                    } catch (Exception e) {
                        addConfigurationFailure(project, state, e, context);
                    } finally {
                        // 5. 將 project 狀態(tài)設(shè)置為 IN_AFTER_EVALUATE
                        state.toAfterEvaluate();
                        // 6. 調(diào)用 ProjectEvaluationListener 的 afterEvaluate()
                        buildOperationExecutor.run(new NotifyAfterEvaluate(project, state));
                    }
                }

                if (state.hasFailure()) {
                    state.rethrowFailure();
                } else {
                    context.setResult(ConfigureProjectBuildOperationType.RESULT);
                }
            } finally {
                // 7. 將 project 狀態(tài)設(shè)置為 CONFIGURED
                state.configured();
            }
        }
    });
}

// NotifyBeforeEvaluate(內(nèi)部類)
public void run(BuildOperationContext context) {
    try {
        project.getProjectEvaluationBroadcaster().beforeEvaluate(project);
        context.setResult(NotifyProjectBeforeEvaluatedBuildOperationType.RESULT);
    } catch (Exception e) {
        addConfigurationFailure(project, state, e, context);
    }
}

// NotifyAfterEvaluate (內(nèi)部類)
public void run(BuildOperationContext context) {
    ProjectEvaluationListener nextBatch = project.getProjectEvaluationBroadcaster();
    Action<ProjectEvaluationListener> fireAction = new Action<ProjectEvaluationListener>() {
        @Override
        public void execute(ProjectEvaluationListener listener) {
            listener.afterEvaluate(project, state);
        }
    };
    // ...
}

可以看到這里主要做了如下事情:

  1. 將 project 的狀態(tài)設(shè)置為 IN_BEFORE_EVALUATE坯台;
  2. 調(diào)用 ProjectEvaluationListenerbeforeEvaluate()炬丸;
  3. 將 project 的狀態(tài)設(shè)置為 IN_EVALUATE
  4. 調(diào)用 ConfigureActionsProjectEvaluatorevaluate()蜒蕾;
  5. 將 project 的狀態(tài)設(shè)置為 IN_AFTER_EVALUATE稠炬;
  6. 調(diào)用 ProjectEvaluationListenerafterEvaluate()
  7. 將 project 的狀態(tài)設(shè)置為 CONFIGURED咪啡。

接下來看 ConfigureActionsProjectEvaluatorevaluate()首启。

// ConfigureActionsProjectEvaluator.java
public void evaluate(ProjectInternal project, ProjectStateInternal state) {
    for (ProjectConfigureAction configureAction : configureActions) {
        configureAction.execute(project);
    }
}

這里調(diào)用了 configureActionsexecute(),也就是前面在創(chuàng)建 ConfigureActionsProjectEvaluator 時(shí)傳入的 PluginsProjectConfigureActions.from(cachingServiceLocator)BuildScriptProcessorexecute()撤摸;前者已經(jīng)分析了毅桃,是給 project 注冊(cè)一些任務(wù);而后者就是解析執(zhí)行 build.gradle 了准夷,來看看其源碼钥飞。

// BuildScriptProcessor.java
public void execute(final ProjectInternal project) {
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("Evaluating {} using {}.", project, project.getBuildScriptSource().getDisplayName());
    }
    final Timer clock = Time.startTimer();
    try {
        final ScriptPlugin configurer = configurerFactory.create(project.getBuildScriptSource(), project.getBuildscript(), project.getClassLoaderScope(), project.getBaseClassLoaderScope(), true);
        project.getMutationState().withMutableState(new Runnable() {
            @Override
            public void run() {
                configurer.apply(project);
            }
        });
    }
}

到這里,root project 和 sub project 也就配置完了衫嵌。

2.2.4 調(diào)用 BuildListener 的 projectsEvaluated()

回到 DefaultProjectPreparerprepareProjects()读宙,接著 configureHierarchy() 往后看。

// DefaultProjectPreparer.java
public void prepareProjects(GradleInternal gradle) {
    maybeInformAboutIncubatingMode(gradle);

    buildLoader.load(gradle.getSettings(), gradle);

    if (gradle.getParent() == null) {
        buildRegistry.beforeConfigureRootBuild();
    }
    if (gradle.getStartParameter().isConfigureOnDemand()) {
        projectConfigurer.configure(gradle.getRootProject());
    } else {
        projectConfigurer.configureHierarchy(gradle.getRootProject());
        // 創(chuàng)建 ProjectsEvaluatedNotifier 楔绞,調(diào)用 notify()
        new ProjectsEvaluatedNotifier(buildOperationExecutor).notify(gradle);
    }
}

它創(chuàng)建了 ProjectsEvaluatedNotifier论悴,并調(diào)用了 notify()

// ProjectsEvaluatedNotifier.java
public void notify(GradleInternal gradle) {
    buildOperationExecutor.run(new NotifyProjectsEvaluatedListeners(gradle));
}

// NotifyProjectsEvaluatedListeners(內(nèi)部類)
private class NotifyProjectsEvaluatedListeners implements RunnableBuildOperation {
    @Override
    public void run(BuildOperationContext context) {
        gradle.getBuildListenerBroadcaster().projectsEvaluated(gradle);
    }
}

這里最終調(diào)用了 BuildListenerprojectsEvaluated()墓律;最后回到 DefaultGradleLauncherprepareProjects()膀估。

// DefaultGradleLauncher.java
private void prepareProjects() {
    if (stage == Stage.LoadSettings) {
        projectsPreparer.prepareProjects(gradle);
        // 設(shè)置狀態(tài)為 Configure
        stage = Stage.Configure;
    }
}

執(zhí)行完 prepareProjects() 后,會(huì)將狀態(tài)設(shè)置為 Configure耻讽。至此察纯,Gradle 的 Configure 階段就分析完了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市饼记,隨后出現(xiàn)的幾起案子香伴,更是在濱河造成了極大的恐慌,老刑警劉巖具则,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件即纲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡博肋,警方通過查閱死者的電腦和手機(jī)低斋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匪凡,“玉大人膊畴,你說我怎么就攤上這事〔∮危” “怎么了唇跨?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衬衬。 經(jīng)常有香客問我买猖,道長,這世上最難降的妖魔是什么滋尉? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任政勃,我火速辦了婚禮,結(jié)果婚禮上兼砖,老公的妹妹穿的比我還像新娘奸远。我一直安慰自己,他們只是感情好讽挟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布懒叛。 她就那樣靜靜地躺著,像睡著了一般耽梅。 火紅的嫁衣襯著肌膚如雪薛窥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天眼姐,我揣著相機(jī)與錄音诅迷,去河邊找鬼。 笑死众旗,一個(gè)胖子當(dāng)著我的面吹牛罢杉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贡歧,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼滩租,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼赋秀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起律想,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤猎莲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后技即,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體著洼,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年而叼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了身笤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡澈歉,死狀恐怖展鸡,靈堂內(nèi)的尸體忽然破棺而出屿衅,到底是詐尸還是另有隱情埃难,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布涤久,位于F島的核電站涡尘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏响迂。R本人自食惡果不足惜考抄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蔗彤。 院中可真熱鬧川梅,春花似錦、人聲如沸然遏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽待侵。三九已至丢早,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間秧倾,已是汗流浹背怨酝。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留那先,地道東北人农猬。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像售淡,于是被迫代替她去往敵國和親盛险。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瞄摊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354