Gradle 源碼分析(四)

1. 寫在前面

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

2. TaskGraph

2.1 整體實現(xiàn)

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

2.1.1 時序圖

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


TaskGraph 時序圖.png

2.1.2 主要操作

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

  1. 執(zhí)行 ExcludedTaskFilteringBuildConfigurationAction,這里會解析 -x--exclude-task 參數(shù)指定需要過濾的 tasks牌里;
  2. 執(zhí)行 DefaultTaskBuildExecutionAction颊咬,這里在沒有指定需要執(zhí)行的 tasks 時务甥,給 default project 設(shè)置 default tasks,并給 StartParameter 設(shè)置執(zhí)行的 tasks喳篇;
  3. 執(zhí)行 TaskNameResolvingBuildConfigurationAction敞临,這里會解析查找符合條件的 tasks ,并添加到 TaskGraph 中(tasks之間的依賴關(guān)系解析比如 dependsOn 就是在這里做的)麸澜;
  4. 填充 TaskGraph挺尿,生成 task 的有向無環(huán)圖;
  5. 如果是指定了 --configure-on-demand 參數(shù)炊邦,調(diào)用 BuildListenerprojectsEvaluated()编矾。

2.2 源碼分析

2.2.1 執(zhí)行 ExcludedTaskFilteringBuildConfigurationAction

TaskGraph 過程是發(fā)生在 DefaultGradleLauncherprepareTaskExecution(),先來看看它的源碼馁害。

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

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

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

BuildOperatingFiringTaskExecutionPreparer 對象,來看看其 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();
    }
}

可以看到凹蜈,最終會調(diào)用到 DefaultTaskExecutionPreparerprepareForTaskExecution(),再來看看它的源碼忍啸。

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

這里的 buildConfigurationActionExecuter 是通過反射調(diào)用的 GradleScopeServicescreateBuildConfigurationActionExecuter()仰坦,來看看其源碼。

// 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 對象计雌。注意這里的三個比較重要的 BuildConfigurationAction悄晃。

  • DefaultTasksBuildExecutionAction
  • TaskNameResolvingBuildConfigurationAction
  • ExcludedTaskFilteringBuildConfigurationAction

先看看 DefaultBuildConfigurationActionExecuterselect()

// DefaultBuildConfigurationActionExecuter.java
public void select(final GradleInternal gradle) {
    projectStateRegistry.withLenientState(new Runnable() {
        @Override
        public void run() {
            // 1. 會調(diào)用到這里
            List<BuildConfigurationAction> processingBuildActions = CollectionUtils.flattenCollections(BuildConfigurationAction.class, configurationActions, taskSelectors);
            // 2. 這里會遍歷 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)過 CollectionUtils.flattenCollections() 處理后白粉,三個 BuildConfigurationAction 的順序是這樣的传泊。

  1. ExcludedTaskFilteringBuildConfigurationAction
  2. DefaultTasksBuildExecutionAction
  3. TaskNameResolvingBuildConfigurationAction

接著調(diào)用了 configure() 遍歷所有的 BuildConfigurationAction,并調(diào)用他們的 configure()鸭巴。也就是說首先會執(zhí)行 ExcludedTaskFilteringBuildConfigurationActionconfigure()眷细,來看看它做了什么。

// ExcludedTaskFilteringBuildConfigurationAction.java
public void configure(BuildExecutionContext context) {
    GradleInternal gradle = context.getGradle();
    // 1. 這里會獲取通過參數(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. 通過 useFilter() 將 Spec 設(shè)置給 TaskGraph
        gradle.getTaskGraph().useFilter(Specs.intersect(filters));
    }
    // 4. 調(diào)用下一個 BuildConfigurationAction 的 configure()
    context.proceed();
}

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

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

這里主要看一下 taskSelector.getFilter(taskName) 的解析過程;taskSelectorTaskSelector 的實例养铸,來看看其 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())) {
            // 能找到確切的則直接返回轧膘,這種能直接通過 path 過濾 task,避免配置 sub projects
            return new TaskPathSpec(targetProject, taskPath.getTaskName());
        }
    }

    // 3. 調(diào)用 getSelection() 找 project  (必要時也會查找 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 沒有指定具體的 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. 必要時調(diào)用 configure() 對 task 所依賴的 project 進(jìn)行配置澡匪。這里可能有的童鞋會存在些許疑問熔任,在 Gradle 的 Configure 階段明明已經(jīng)配置過了 project,為什么這里還要再配置一次仙蛉;舉個栗子笋敞,比如在 app 目錄下執(zhí)行 .././gradlew clean --configure-on-demand,在 Configure 階段因為有 --configure-on-demand 參數(shù)荠瘪,只會配置 root project,而 clean task 所依賴的 app project 并沒有經(jīng)過配置赛惩,所以這里需要有這個邏輯防止所執(zhí)行的 task 依賴的 project 沒有進(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)) {
        // 拿最后一個 : 的索引
        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() 了,來看看其源碼勉抓。

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

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

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

    if (defaultTasks.size() == 0) {
        // 3. 如果 default project 沒有設(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)用下一個 BuildConfigurationAction 的 configure()
    context.proceed();
}

DefaultTaskBuildExecutionAction 的邏輯也十分的清晰:

  1. 先判斷是否有指定需要執(zhí)行的 task,如果有指定盐碱,則直接返回把兔,比如 ./gradlew clean沪伙,這種就是指定了執(zhí)行 clean task;
  2. 如果沒有指定則需要執(zhí)行的 task垛贤,比如 ./gradlew焰坪,則獲取 default project 的 default tasks,如果沒有設(shè)置 default tasks聘惦,則使用 help task 作為 default tasks某饰;
  3. 如果有設(shè)置 default tasks,則不作操作善绎;
  4. 給 StartParameter 指定需要執(zhí)行的 tasks黔漂,即 default tasks;
  5. 調(diào)用下一個 BuildConfigurationActionconfigure()禀酱。

舉個簡單的栗子方便理解炬守。在 app 下執(zhí)行 .././gradlew 腳本,這個時候 default project 即 app 對應(yīng)的 project剂跟。在執(zhí)行到 DefaultTaskBuildExecutionAction 的時候减途,因為 app 的 build.gradle 里面是沒有配置 default tasks 的,所以這里會設(shè)置 help task 為 default task曹洽,也就是上面命令執(zhí)行 task 實際上是 help task鳍置。

help task.png

這個時候,修改 app 的 build.gradle 送淆。

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

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

hello task.png

2.2.3 執(zhí)行 TaskNameResolvingBuildConfigurationAction

執(zhí)行完 DefaultTaskBuildExecutionActionconfigure()辟拷,緊接著就是執(zhí)行 TaskNameResolvingBuildConfigurationActionconfigure() 了,來看看其源碼阐斜。

// 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) 的解析過程。

// 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;
}

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

看完解析過程颜骤,再來看看添加過程 taskGraph.addEntryTasks(taskSelection.getTasks())taskGraphDefaultTaskExecutionGraph捣卤,來看看其 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() 就會處理 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 獲取到的需要過濾的 
            node.require();
        }
        entryTasks.add(node);
        queue.add(node);
    }

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

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

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

        if (visiting.add(node)) {
            node.prepareForExecution();
            // 主要是這個方法,里面處理依賴關(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);
}

重點看一下 node.resolveDependencies()祟绊;這里的 node 是通過 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 對象,來看看其 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();
    // 計算有向無環(huán)圖
    taskGraph.populate();
    // ...
}

這里會調(diào)用了 DefaultTaskExecutionGraphpopulate()阐肤,來看看其源碼。

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

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

在前面添加 task 的時候讲坎,已經(jīng)將 graphState 標(biāo)記為了 DIRTY 狀態(tài)孕惜,所以這里會走到 executionPlan.determineExecutionPlan()executionPlanDefaultExecutionPlan 的實例晨炕,來看看其 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);
}

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

2.2.5 必要時調(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 的有向無環(huán)圖后遵馆,會判斷是否有指定 --configure-on-demand 參數(shù),如果有指定丰榴,則調(diào)用 BuildListenerprojectEvaluated() 货邓,因為在 Configure 階段,--configure-on-demand 只會對 root project 進(jìn)行配置四濒,如果對 Configure 階段不太熟悉的换况,可以先看看 Gradle源碼分析(三)

最后盗蟆,回到 DefaultGradleLauncherprepareTaskExecution()戈二。

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末仆邓,一起剝皮案震驚了整個濱河市鲜滩,隨后出現(xiàn)的幾起案子伴鳖,更是在濱河造成了極大的恐慌,老刑警劉巖徙硅,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榜聂,死亡現(xiàn)場離奇詭異,居然都是意外死亡嗓蘑,警方通過查閱死者的電腦和手機(jī)须肆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脐往,“玉大人休吠,你說我怎么就攤上這事∫挡荆” “怎么了瘤礁?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長梅尤。 經(jīng)常有香客問我柜思,道長,這世上最難降的妖魔是什么巷燥? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任赡盘,我火速辦了婚禮,結(jié)果婚禮上缰揪,老公的妹妹穿的比我還像新娘陨享。我一直安慰自己,他們只是感情好钝腺,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布抛姑。 她就那樣靜靜地躺著,像睡著了一般艳狐。 火紅的嫁衣襯著肌膚如雪定硝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天毫目,我揣著相機(jī)與錄音蔬啡,去河邊找鬼。 笑死镀虐,一個胖子當(dāng)著我的面吹牛箱蟆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播粉私,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼顽腾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起抄肖,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤久信,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后漓摩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裙士,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年管毙,在試婚紗的時候發(fā)現(xiàn)自己被綠了腿椎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡夭咬,死狀恐怖啃炸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卓舵,我是刑警寧澤南用,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站掏湾,受9級特大地震影響裹虫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜融击,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一筑公、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尊浪,春花似錦匣屡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至工育,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間搓彻,已是汗流浹背如绸。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留旭贬,地道東北人怔接。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像稀轨,于是被迫代替她去往敵國和親扼脐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354