Gradle 源碼分析(四)

1. 寫在前面

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

2. TaskGraph

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

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

2.1.1 時(shí)序圖

這里只繪制了關(guān)鍵的方法鏈,一些比較細(xì)的在源碼部分有說(shuō)到。


TaskGraph 時(shí)序圖.png

2.1.2 主要操作

TaskGraph 階段 Gradle 主要做了下面這些事情。

  1. 執(zhí)行 ExcludedTaskFilteringBuildConfigurationAction,這里會(huì)解析 -x--exclude-task 參數(shù)指定需要過(guò)濾的 tasks;
  2. 執(zhí)行 DefaultTaskBuildExecutionAction,這里在沒(méi)有指定需要執(zhí)行的 tasks 時(shí),給 default project 設(shè)置 default tasks,并給 StartParameter 設(shè)置執(zhí)行的 tasks;
  3. 執(zhí)行 TaskNameResolvingBuildConfigurationAction,這里會(huì)解析查找符合條件的 tasks ,并添加到 TaskGraph 中(tasks之間的依賴關(guān)系解析比如 dependsOn 就是在這里做的);
  4. 填充 TaskGraph,生成 task 的有向無(wú)環(huán)圖;
  5. 如果是指定了 --configure-on-demand 參數(shù),調(diào)用 BuildListenerprojectsEvaluated()

2.2 源碼分析

2.2.1 執(zhí)行 ExcludedTaskFilteringBuildConfigurationAction

TaskGraph 過(guò)程是發(fā)生在 DefaultGradleLauncherprepareTaskExecution(),先來(lái)看看它的源碼。

// DefaultGradleLauncher.java
private void prepareTaskExecution() {
    if (stage == Stage.Configure) {
        taskExecutionPreparer.prepareForTaskExecution(gradle);
        // ...
    }
}

這里的 taskExecutionPreparer 是通過(guò)反射調(diào)用的 GradleScopeServicescreateTaskExecutionPreparer()。

// GradleScopeServices.java
TaskExecutionPreparer createTaskExecutionPreparer(BuildConfigurationActionExecuter buildConfigurationActionExecuter, IncludedBuildControllers includedBuildControllers, BuildOperationExecutor buildOperationExecutor) {
    return new BuildOperatingFiringTaskExecutionPreparer(
        new DefaultTaskExecutionPreparer(buildConfigurationActionExecuter, includedBuildControllers, buildOperationExecutor),
        buildOperationExecutor);
}

BuildOperatingFiringTaskExecutionPreparer 對(duì)象,來(lái)看看其 prepareForTaskExecution()。

// BuildOperatingFiringTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
    buildOperationExecutor.run(new CalculateTaskGraph(gradle));
}

private class CalculateTaskGraph implements RunnableBuildOperation {

    @Override
    public void run(BuildOperationContext buildOperationContext) {
        final TaskExecutionGraphInternal taskGraph = populateTaskGraph();
        // ...
    }

    TaskExecutionGraphInternal populateTaskGraph() {
        // 調(diào)用到了 DefaultTaskExecutionPreparer 的 prepareForTaskExecution()
        delegate.prepareForTaskExecution(gradle);
        return gradle.getTaskGraph();
    }
}

可以看到,最終會(huì)調(diào)用到 DefaultTaskExecutionPreparerprepareForTaskExecution(),再來(lái)看看它的源碼。

// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
    buildConfigurationActionExecuter.select(gradle);
    // ... 省略部分代碼
}

這里的 buildConfigurationActionExecuter 是通過(guò)反射調(diào)用的 GradleScopeServicescreateBuildConfigurationActionExecuter(),來(lái)看看其源碼。

// GradleScopeServices.java
BuildConfigurationActionExecuter createBuildConfigurationActionExecuter(CommandLineTaskParser commandLineTaskParser, TaskSelector taskSelector, ProjectConfigurer projectConfigurer, ProjectStateRegistry projectStateRegistry) {
    List<BuildConfigurationAction> taskSelectionActions = new LinkedList<BuildConfigurationAction>();
    // 添加 DefaultTasksBuildExecutionAction
    taskSelectionActions.add(new DefaultTasksBuildExecutionAction(projectConfigurer));
    // 添加 TaskNameResolvingBuildConfigurationAction
    taskSelectionActions.add(new TaskNameResolvingBuildConfigurationAction(commandLineTaskParser));
    // 添加 ExcludedTaskFilteringBuildConfigurationAction
    return new DefaultBuildConfigurationActionExecuter(Arrays.asList(new ExcludedTaskFilteringBuildConfigurationAction(taskSelector)), taskSelectionActions, projectStateRegistry);
}

DefaultBuildConfigurationActionExecuter 對(duì)象。注意這里的三個(gè)比較重要的 BuildConfigurationAction。

  • DefaultTasksBuildExecutionAction
  • TaskNameResolvingBuildConfigurationAction
  • ExcludedTaskFilteringBuildConfigurationAction

先看看 DefaultBuildConfigurationActionExecuterselect()。

// DefaultBuildConfigurationActionExecuter.java
public void select(final GradleInternal gradle) {
    projectStateRegistry.withLenientState(new Runnable() {
        @Override
        public void run() {
            // 1. 會(huì)調(diào)用到這里
            List<BuildConfigurationAction> processingBuildActions = CollectionUtils.flattenCollections(BuildConfigurationAction.class, configurationActions, taskSelectors);
            // 2. 這里會(huì)遍歷 processingBuildActions 分別調(diào)用它們的 configure()
            configure(processingBuildActions, gradle, 0);
        }
    });
}

private void configure(final List<BuildConfigurationAction> processingConfigurationActions, final GradleInternal gradle, final int index) {
    if (index >= processingConfigurationActions.size()) {
        return;
    }
    processingConfigurationActions.get(index).configure(new BuildExecutionContext() {
        @Override
        public void proceed() {
            configure(processingConfigurationActions, gradle, index + 1);
        }
    });
}

select() 里面經(jīng)過(guò) CollectionUtils.flattenCollections() 處理后,三個(gè) BuildConfigurationAction 的順序是這樣的。

  1. ExcludedTaskFilteringBuildConfigurationAction
  2. DefaultTasksBuildExecutionAction
  3. TaskNameResolvingBuildConfigurationAction

接著調(diào)用了 configure() 遍歷所有的 BuildConfigurationAction,并調(diào)用他們的 configure()。也就是說(shuō)首先會(huì)執(zhí)行 ExcludedTaskFilteringBuildConfigurationActionconfigure(),來(lái)看看它做了什么。

// ExcludedTaskFilteringBuildConfigurationAction.java
public void configure(BuildExecutionContext context) {
    GradleInternal gradle = context.getGradle();
    // 1. 這里會(huì)獲取通過(guò)參數(shù) -x 或者 --exclude-task 指定的 tasks
    Set<String> excludedTaskNames = gradle.getStartParameter().getExcludedTaskNames();
    if (!excludedTaskNames.isEmpty()) {
        final Set<Spec<Task>> filters = new HashSet<Spec<Task>>();
        for (String taskName : excludedTaskNames) {
            // 2. 解析這些 tasks,封裝成 Spec<Task>
            filters.add(taskSelector.getFilter(taskName));
        }
        // 3. 通過(guò) useFilter() 將 Spec 設(shè)置給 TaskGraph
        gradle.getTaskGraph().useFilter(Specs.intersect(filters));
    }
    // 4. 調(diào)用下一個(gè) BuildConfigurationAction 的 configure()
    context.proceed();
}

可以看到,ExcludedTaskFilteringBuildConfigurationAction 的流程如下:

  1. 獲取通過(guò)參數(shù) -x 或者 --exclude-task 指定的需要過(guò)濾的 tasks;
  2. 遍歷這些 tasks,進(jìn)行解析后封裝成 Spec<Task>;
  3. 通過(guò) useFilter() 設(shè)置給 TaskGraph,為后面構(gòu)建 TaskGraph 做準(zhǔn)備;
  4. 調(diào)用下一個(gè) BuildConfigurationActionconfigure()。

這里主要看一下 taskSelector.getFilter(taskName) 的解析過(guò)程;taskSelectorTaskSelector 的實(shí)例,來(lái)看看其 getFilter() 的源碼。

// TaskSelector.java
public Spec<Task> getFilter(String path) {
    // 1. 調(diào)用 taskPathResolver 的 resolvePath 解析 task
    final ResolvedTaskPath taskPath = taskPathResolver.resolvePath(path, gradle.getDefaultProject());
    if (!taskPath.isQualified()) {
        ProjectInternal targetProject = taskPath.getProject();
        // 2. 配置task依賴的project
        configurer.configure(targetProject);
        if (taskNameResolver.tryFindUnqualifiedTaskCheaply(taskPath.getTaskName(), taskPath.getProject())) {
            // 能找到確切的則直接返回,這種能直接通過(guò) path 過(guò)濾 task,避免配置 sub projects
            return new TaskPathSpec(targetProject, taskPath.getTaskName());
        }
    }

    // 3. 調(diào)用 getSelection() 找 project  (必要時(shí)也會(huì)查找 sub project) 下所有符合的 tasks
    final Set<Task> selectedTasks = getSelection(path, gradle.getDefaultProject()).getTasks();
    return new Spec<Task>() {
        @Override
        public boolean isSatisfiedBy(Task element) {
            return !selectedTasks.contains(element);
        }
    };
}

private TaskSelection getSelection(String path, ProjectInternal project) {
    ResolvedTaskPath taskPath = taskPathResolver.resolvePath(path, project);
    ProjectInternal targetProject = taskPath.getProject();
    if (taskPath.isQualified()) {
        // path 指定有具體的 project,比如 :app:clean,則配置具體的 project
        configurer.configure(targetProject);
    } else {
        // path 沒(méi)有指定具體的 project,比如 clean,則配置 project 和 sub project
        configurer.configureHierarchy(targetProject);
    }
    // 查找所有符合條件的 tasks
    TaskSelectionResult tasks = taskNameResolver.selectWithName(taskPath.getTaskName(), taskPath.getProject(), !taskPath.isQualified());
    if (tasks != null) {
        return new TaskSelection(taskPath.getProject().getPath(), path, tasks);
    }
    // 查找所有符合條件的 tasks
    Map<String, TaskSelectionResult> tasksByName = taskNameResolver.selectAll(taskPath.getProject(), !taskPath.isQualified());
    NameMatcher matcher = new NameMatcher();
    String actualName = matcher.find(taskPath.getTaskName(), tasksByName.keySet());
    if (actualName != null) {
        return new TaskSelection(taskPath.getProject().getPath(), taskPath.getPrefix() + actualName, tasksByName.get(actualName));
    }

    throw new TaskSelectionException(matcher.formatErrorMessage("task", taskPath.getProject()));
}

getFilter() 方法的邏輯也很清晰;

  1. 調(diào)用 TaskPathResolverresolvePath() 解析 task;
  2. 必要時(shí)調(diào)用 configure() 對(duì) task 所依賴的 project 進(jìn)行配置。這里可能有的童鞋會(huì)存在些許疑問(wèn),在 Gradle 的 Configure 階段明明已經(jīng)配置過(guò)了 project,為什么這里還要再配置一次;舉個(gè)栗子,比如在 app 目錄下執(zhí)行 .././gradlew clean --configure-on-demand,在 Configure 階段因?yàn)橛?--configure-on-demand 參數(shù),只會(huì)配置 root project,而 clean task 所依賴的 app project 并沒(méi)有經(jīng)過(guò)配置,所以這里需要有這個(gè)邏輯防止所執(zhí)行的 task 依賴的 project 沒(méi)有進(jìn)行配置的情況;
  3. 調(diào)用 getSelection() 找所有符合的 tasks,并封裝成 Spec<Task> 返回。

這里主要看下 resolvePath() 的源碼。

// TaskPathResolver.java
public ResolvedTaskPath resolvePath(String path, ProjectInternal startFrom) {
    ProjectInternal project;
    String taskName; //eg. 'someTask' or 'sT'
    String prefix; //eg. '', ':' or ':foo:bar'
    
    // 如果 path 包含有 : 分隔符,比如 :app:assembleDebug
    if (path.contains(Project.PATH_SEPARATOR)) {
        // 拿最后一個(gè) : 的索引
        int idx = path.lastIndexOf(Project.PATH_SEPARATOR);
        // taskName = assembleDebug
        taskName = path.substring(idx + 1);
        // prefix = :app:
        prefix = path.substring(0, idx+1);
        // projectPath = :app
        String projectPath = Project.PATH_SEPARATOR.equals(prefix) ? prefix : path.substring(0, idx);
        // 找 project
        project = projectFinder.findProject(projectPath, startFrom);
    } else {
        // 如果path 就是純粹的 taskName,比如 clean
        // project = default project
        project = startFrom;
        // taskName = clean 
        taskName = path;
        // prefix = ""
        prefix = "";
    }
    return new ResolvedTaskPath(prefix, taskName, project);
}

2.2.2 執(zhí)行 DefaultTaskBuildExecutionAction

執(zhí)行完 ExcludedTaskFilteringBuildConfigurationActionconfigure(),緊接著就是執(zhí)行 DefaultTaskBuildExecutionActionconfigure() 了,來(lái)看看其源碼。

// DefaultTaskBuildExecutionAction.java
public void configure(BuildExecutionContext context) {
    StartParameter startParameter = context.getGradle().getStartParameter();

    // 1. 首先看有沒(méi)有指定執(zhí)行的 task,如果有指定執(zhí)行的 task,則直接返回;比如 ./gradlew clean,指定了需要執(zhí)行 clean task,這里的 args 即 clean
    for (TaskExecutionRequest request : startParameter.getTaskRequests()) {
        if (!request.getArgs().isEmpty()) {
            context.proceed();
            return;
        }
    }

    // 2. 如果沒(méi)有指定要執(zhí)行的task,則獲取 default project 的 default tasks,比如執(zhí)行 ./gradlew ,這種就是沒(méi)有指定執(zhí)行的 task
    ProjectInternal project = context.getGradle().getDefaultProject();
    projectConfigurer.configure(project);
    List<String> defaultTasks = project.getDefaultTasks();

    if (defaultTasks.size() == 0) {
        // 3. 如果 default project 沒(méi)有設(shè)置 default tasks,則指定為 help task
        defaultTasks = Collections.singletonList(ProjectInternal.HELP_TASK);
        LOGGER.info("No tasks specified. Using default task {}", GUtil.toString(defaultTasks));
    } else {
        // 4. 如果 default project 有設(shè)置 default tasks,則使用設(shè)置的 default tasks
        LOGGER.info("No tasks specified. Using project default tasks {}", GUtil.toString(defaultTasks));
    }
    // 5. 設(shè)置需要執(zhí)行的 tasks
    startParameter.setTaskNames(defaultTasks);
    // 6. 調(diào)用下一個(gè) BuildConfigurationAction 的 configure()
    context.proceed();
}

DefaultTaskBuildExecutionAction 的邏輯也十分的清晰:

  1. 先判斷是否有指定需要執(zhí)行的 task,如果有指定,則直接返回,比如 ./gradlew clean,這種就是指定了執(zhí)行 clean task;
  2. 如果沒(méi)有指定則需要執(zhí)行的 task,比如 ./gradlew,則獲取 default project 的 default tasks,如果沒(méi)有設(shè)置 default tasks,則使用 help task 作為 default tasks;
  3. 如果有設(shè)置 default tasks,則不作操作;
  4. 給 StartParameter 指定需要執(zhí)行的 tasks,即 default tasks;
  5. 調(diào)用下一個(gè) BuildConfigurationActionconfigure()。

舉個(gè)簡(jiǎn)單的栗子方便理解。在 app 下執(zhí)行 .././gradlew 腳本,這個(gè)時(shí)候 default project 即 app 對(duì)應(yīng)的 project。在執(zhí)行到 DefaultTaskBuildExecutionAction 的時(shí)候,因?yàn)?app 的 build.gradle 里面是沒(méi)有配置 default tasks 的,所以這里會(huì)設(shè)置 help task 為 default task,也就是上面命令執(zhí)行 task 實(shí)際上是 help task。

help task.png

這個(gè)時(shí)候,修改 app 的 build.gradle 。

Task hello = task("hello") {
    doLast {
        println("hello, gradle")
    }
}
List<String> tasks = new ArrayList<String>()
tasks.add(hello.name)
setDefaultTasks(tasks)

通過(guò) setDefaultTasks() 設(shè)置 default tasks 是 hello task。這個(gè)時(shí)候再執(zhí)行 .././gradlew 腳本,它執(zhí)行的就是 hello task。

hello task.png

2.2.3 執(zhí)行 TaskNameResolvingBuildConfigurationAction

執(zhí)行完 DefaultTaskBuildExecutionActionconfigure(),緊接著就是執(zhí)行 TaskNameResolvingBuildConfigurationActionconfigure() 了,來(lái)看看其源碼。

// TaskNameResolvingBuildConfigurationAction.java
public void configure(BuildExecutionContext context) {
    GradleInternal gradle = context.getGradle();
    TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
    // 1. 獲取指定執(zhí)行的 TaskExecutionRequest
    List<TaskExecutionRequest> taskParameters = gradle.getStartParameter().getTaskRequests();
    for (TaskExecutionRequest taskParameter : taskParameters) {
        // 2. 解析 task,查找符合的 tasks
        List<TaskSelector.TaskSelection> taskSelections = commandLineTaskParser.parseTasks(taskParameter);
        for (TaskSelector.TaskSelection taskSelection : taskSelections) {
            // 3. 添加所有符合的 tasks 到 TaskGraph
            taskGraph.addEntryTasks(taskSelection.getTasks());
        }
    }

    context.proceed();
}

這里先看一下 commandLineTaskParser.parseTasks(taskParameter) 的解析過(guò)程。

// CommandLineTaskParser.java
public List<TaskSelector.TaskSelection> parseTasks(TaskExecutionRequest taskExecutionRequest) {
    List<TaskSelector.TaskSelection> out = Lists.newArrayList();
    // 比如 :app:clean,args 即 [:app:clean]
    List<String> remainingPaths = new LinkedList<String>(taskExecutionRequest.getArgs());
    while (!remainingPaths.isEmpty()) {
        String path = remainingPaths.remove(0);
        // 和 getFilter() 里面一樣,調(diào)用 getSelection() 查找所有符合的 tasks
        TaskSelector.TaskSelection selection = taskSelector.getSelection(taskExecutionRequest.getProjectPath(), taskExecutionRequest.getRootDir(), path);
        Set<Task> tasks = selection.getTasks();
        remainingPaths = taskConfigurer.configureTasks(tasks, remainingPaths);
        out.add(selection);
    }
    return out;
}

舉個(gè)栗子,比如在 app 下面執(zhí)行 .././gradlew :app:clean,這里的 taskExecutionRequest.getArgs()[:app:clean],然后會(huì)根據(jù)這個(gè) path 去查找所有符合的 tasks,再添加到 TaskGraph 里面。

看完解析過(guò)程,再來(lái)看看添加過(guò)程 taskGraph.addEntryTasks(taskSelection.getTasks()),taskGraphDefaultTaskExecutionGraph,來(lái)看看其 addEntryTasks()。

// DefaultTaskExecutionGraph.java
public void addEntryTasks(Iterable<? extends Task> tasks) {
    Set<Task> taskSet = new LinkedHashSet<Task>();
    for (Task task : tasks) {
        taskSet.add(task);
        requestedTasks.add(task);
    }
    // 調(diào)用 DefaultExecutionPlan.addEntryTasks()
    executionPlan.addEntryTasks(taskSet);
    // task graph 標(biāo)記為 DIRTY 狀態(tài)
    graphState = GraphState.DIRTY;
}

這里主要做了兩件事情:

  1. 調(diào)用 DefaultExecutionPlanaddEntryTasks();
  2. TaskGraph 的狀態(tài)標(biāo)記為 DIRTY。

而這里的 addEntryTasks() 就會(huì)處理 task 之間的依賴關(guān)系,比如 dependsOn等。

// DefaultExecutionPlan.java
public void addEntryTasks(Collection<? extends Task> tasks) {
    final Deque<Node> queue = new ArrayDeque<Node>();
    Set<Node> nodesInUnknownState = Sets.newLinkedHashSet();

    List<Task> sortedTasks = new ArrayList<Task>(tasks);
    Collections.sort(sortedTasks);
    for (Task task : sortedTasks) {
        TaskNode node = taskNodeFactory.getOrCreateNode(task);
        if (node.isMustNotRun()) {
            requireWithDependencies(node);
        } else if (filter.isSatisfiedBy(task)) {
            // 這里就是前面 ExcludedTaskFilteringBuildConfigurationAction 獲取到的需要過(guò)濾的 
            node.require();
        }
        entryTasks.add(node);
        queue.add(node);
    }

    final Set<Node> visiting = Sets.newHashSet();

    while (!queue.isEmpty()) {
        Node node = queue.getFirst();
        // 已經(jīng)處理過(guò)了
        if (node.getDependenciesProcessed()) {
            queue.removeFirst();
            continue;
        }

        boolean filtered = !nodeSatisfiesTaskFilter(node);
        // 過(guò)濾掉
        if (filtered) {
            queue.removeFirst();
            // 標(biāo)記為處理
            node.dependenciesProcessed();
            node.doNotRequire();
            filteredNodes.add(node);
            continue;
        }

        if (visiting.add(node)) {
            node.prepareForExecution();
            // 主要是這個(gè)方法,里面處理依賴關(guān)系
            node.resolveDependencies(dependencyResolver, new Action<Node>() {
                @Override
                public void execute(Node targetNode) {
                    if (!visiting.contains(targetNode)) {
                        queue.addFirst(targetNode);
                    }
                }
            });
            if (node.isRequired()) {
                for (Node successor : node.getDependencySuccessors()) {
                    if (nodeSatisfiesTaskFilter(successor)) {
                        successor.require();
                    }
                }
            } else {
                nodesInUnknownState.add(node);
            }
        } else {
            queue.removeFirst();
            visiting.remove(node);
            node.dependenciesProcessed();
        }
    }
    resolveNodesInUnknownState(nodesInUnknownState);
}

重點(diǎn)看一下 node.resolveDependencies();這里的 node 是通過(guò) TaskNodeFactorygetOrCreateNode() 創(chuàng)建的。

// TaskNodeFactory.java
public TaskNode getOrCreateNode(Task task) {
    TaskNode node = nodes.get(task);
    if (node == null) {
        if (task.getProject().getGradle() == thisBuild) {
            node = new LocalTaskNode((TaskInternal) task);
        } else {
            node = new TaskInAnotherBuild((TaskInternal) task, currentBuildId, taskGraph);
        }
        nodes.put(task, node);
    }
    return node;
}

LocalTaskNode 對(duì)象,來(lái)看看其 resolveDependencies()。

// LocalTaskNode.java
public void resolveDependencies(TaskDependencyResolver dependencyResolver, Action<Node> processHardSuccessor) {
    // dependsOn 的解析
    for (Node targetNode : getDependencies(dependencyResolver)) {
        addDependencySuccessor(targetNode);
        processHardSuccessor.execute(targetNode);
    }
    // finalizedBy 的解析
    for (Node targetNode : getFinalizedBy(dependencyResolver)) {
        if (!(targetNode instanceof TaskNode)) {
            throw new IllegalStateException("Only tasks can be finalizers: " + targetNode);
        }
        addFinalizerNode((TaskNode) targetNode);
        processHardSuccessor.execute(targetNode);
    }
    // mustRunAfter 的解析
    for (Node targetNode : getMustRunAfter(dependencyResolver)) {
        addMustSuccessor(targetNode);
    }
    // shouldRunAfter 的解析
    for (Node targetNode : getShouldRunAfter(dependencyResolver)) {
        addShouldSuccessor(targetNode);
    }
}

可以看到 task 的依賴關(guān)系解析就是在這里做的。

2.2.4 填充 TaskGraph

回到 DefaultTaskExecutionPreparerprepareForTaskExecution(),繼續(xù)往下看。

// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
    buildConfigurationActionExecuter.select(gradle);

    TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
    // 計(jì)算有向無(wú)環(huán)圖
    taskGraph.populate();
    // ...
}

這里會(huì)調(diào)用了 DefaultTaskExecutionGraphpopulate(),來(lái)看看其源碼。

// DefaultTaskExecutionGraph.java
public void populate() {
    ensurePopulated();
}

private void ensurePopulated() {
    switch (graphState) {
        // ...
        case DIRTY:
            executionPlan.determineExecutionPlan();
            allTasks = null;
            graphState = GraphState.POPULATED;
            return;
        // ...
    }
}

在前面添加 task 的時(shí)候,已經(jīng)將 graphState 標(biāo)記為了 DIRTY 狀態(tài),所以這里會(huì)走到 executionPlan.determineExecutionPlan(),executionPlanDefaultExecutionPlan 的實(shí)例,來(lái)看看其 determineExecutionPlan()。

// DefaultExecutionPlan.java
public void determineExecutionPlan() {
    LinkedList<NodeInVisitingSegment> nodeQueue = Lists.newLinkedList(Iterables.transform(entryTasks, new Function<TaskNode, NodeInVisitingSegment>() {
        private int index;

        @Override
        @SuppressWarnings("NullableProblems")
        public NodeInVisitingSegment apply(TaskNode taskNode) {
            return new NodeInVisitingSegment(taskNode, index++);
        }
    }));
    int visitingSegmentCounter = nodeQueue.size();

    HashMultimap<Node, Integer> visitingNodes = HashMultimap.create();
    Deque<GraphEdge> walkedShouldRunAfterEdges = new ArrayDeque<GraphEdge>();
    Deque<Node> path = new ArrayDeque<Node>();
    Map<Node, Integer> planBeforeVisiting = Maps.newHashMap();

    while (!nodeQueue.isEmpty()) {
        NodeInVisitingSegment nodeInVisitingSegment = nodeQueue.peekFirst();
        int currentSegment = nodeInVisitingSegment.visitingSegment;
        Node node = nodeInVisitingSegment.node;

        if (node.isIncludeInGraph() || nodeMapping.contains(node)) {
            nodeQueue.removeFirst();
            visitingNodes.remove(node, currentSegment);
            maybeRemoveProcessedShouldRunAfterEdge(walkedShouldRunAfterEdges, node);
            continue;
        }

        boolean alreadyVisited = visitingNodes.containsKey(node);
        visitingNodes.put(node, currentSegment);

        if (!alreadyVisited) {
            recordEdgeIfArrivedViaShouldRunAfter(walkedShouldRunAfterEdges, path, node);
            removeShouldRunAfterSuccessorsIfTheyImposeACycle(visitingNodes, nodeInVisitingSegment);
            takePlanSnapshotIfCanBeRestoredToCurrentTask(planBeforeVisiting, node);

            for (Node successor : node.getAllSuccessorsInReverseOrder()) {
                if (visitingNodes.containsEntry(successor, currentSegment)) {
                    if (!walkedShouldRunAfterEdges.isEmpty()) {
                        GraphEdge toBeRemoved = walkedShouldRunAfterEdges.pop();
                        TaskNode sourceTask = (TaskNode) toBeRemoved.from;
                        TaskNode targetTask = (TaskNode) toBeRemoved.to;
                        sourceTask.removeShouldSuccessor(targetTask);
                        restorePath(path, toBeRemoved);
                        restoreQueue(nodeQueue, visitingNodes, toBeRemoved);
                        restoreExecutionPlan(planBeforeVisiting, toBeRemoved);
                        break;
                    } else {
                        onOrderingCycle(successor, node);
                    }
                }
                nodeQueue.addFirst(new NodeInVisitingSegment(successor, currentSegment));
            }
            path.push(node);
        } else {
            nodeQueue.removeFirst();
            maybeRemoveProcessedShouldRunAfterEdge(walkedShouldRunAfterEdges, node);
            visitingNodes.remove(node, currentSegment);
            path.pop();
            nodeMapping.add(node);

            MutationInfo mutations = getOrCreateMutationsOf(node);
            for (Node dependency : node.getDependencySuccessors()) {
                getOrCreateMutationsOf(dependency).consumingNodes.add(node);
                mutations.producingNodes.add(dependency);
            }

            Project project = node.getProject();
            if (project != null) {
                projectLocks.put(project, getOrCreateProjectLock(project));
            }

            for (Node finalizer : node.getFinalizers()) {
                if (!visitingNodes.containsKey(finalizer)) {
                    int position = finalizerTaskPosition(finalizer, nodeQueue);
                    nodeQueue.add(position, new NodeInVisitingSegment(finalizer, visitingSegmentCounter++));
                }
            }
        }
    }
    executionQueue.clear();
    Iterables.addAll(executionQueue, nodeMapping);
}

這個(gè)方法就是填充 TaskGraph,生成 task 的有向無(wú)環(huán)圖。

2.2.5 必要時(shí)調(diào)用 BuildListenerprojectsEvaluated()

繼續(xù)往下看 DefaultTaskExecutionPreparerprepareForTaskExecution()

// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
    buildConfigurationActionExecuter.select(gradle);

    TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
    taskGraph.populate();

    includedBuildControllers.populateTaskGraphs();
    
    // 如果是 --configure-on-demand 的情況下,是在這里調(diào)用的 projectEvaluated
    if (gradle.getStartParameter().isConfigureOnDemand()) {
        new ProjectsEvaluatedNotifier(buildOperationExecutor).notify(gradle);
    }
}

生成 task 的有向無(wú)環(huán)圖后,會(huì)判斷是否有指定 --configure-on-demand 參數(shù),如果有指定,則調(diào)用 BuildListenerprojectEvaluated() ,因?yàn)樵?Configure 階段,--configure-on-demand 只會(huì)對(duì) root project 進(jìn)行配置,如果對(duì) Configure 階段不太熟悉的,可以先看看 Gradle源碼分析(三)。

最后,回到 DefaultGradleLauncherprepareTaskExecution()。

// DefaultGradleLauncher.java
private void prepareTaskExecution() {
    if (stage == Stage.Configure) {
        taskExecutionPreparer.prepareForTaskExecution(gradle);
        // 解析完 tasks 填充 tasks 有向無(wú)環(huán)圖后,將狀態(tài)設(shè)置為 TaskGraph
        stage = Stage.TaskGraph;
    }
}

執(zhí)行完上述流程后會(huì)將 Gradle 狀態(tài)設(shè)置為 TaskGraph。至此,Gradle 的 TaskGraph 階段就分析完了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容