剖析Gradle五大环节源码细节

在官方和源码层面,可以细分为更多步骤。下面我以官方推荐的五大主要阶段为主,每个环节再细化到具体方法、内部逻辑、源码行级剖析,并结合具体场景实例,帮助你真正掌握Gradle的工作机制。


Gradle构建流程五大环节

  1. 启动阶段(Startup)
  2. 初始化阶段(Initialization)
  3. 项目加载阶段(Project Loading)
  4. 配置阶段(Configuration)
  5. 执行阶段(Execution)

1. 启动阶段(Startup)

作用

  • 启动JVM,解析Gradle命令行参数,决定是否用守护进程。

关键方法与内部逻辑

步骤 关键类/方法 说明
1 org.gradle.wrapper.GradleWrapperMain.main() Wrapper入口
2 org.gradle.launcher.GradleMain.main() Gradle主入口
3 CommandLineActionFactory.convert() 解析命令行参数
4 DaemonClient.execute() 是否用守护进程

源码片段(简化)

// org.gradle.wrapper.GradleWrapperMain
public static void main(String[] args) {
    // 判断wrapper配置,启动GradleMain
    GradleMain.main(args);
}

// org.gradle.launcher.GradleMain
public static void main(String[] args) {
    CommandLineActionFactory.convert(args);
    // 判断是否用守护进程
    DaemonClient.execute();
}

场景实例

  • 你在命令行执行 ./gradlew build,其实先运行的是 GradleWrapperMain,再到 GradleMain

速记口诀

“命令启动,参数先行”


2. 初始化阶段(Initialization)

作用

  • 定位构建目录,加载settings.gradle,确定是单项目还是多项目。

关键方法与内部逻辑

步骤 关键类/方法 说明
1 SettingsLoader.findAndLoadSettings() 查找和加载settings.gradle
2 DefaultGradleSettingsProcessor.process() 处理settings逻辑

源码片段

// org.gradle.initialization.SettingsLoader
public SettingsInternal findAndLoadSettings() {
    // 递归查找settings.gradle
    // 解析里面的include等多项目指令
}

场景实例

  • 你有多项目构建,settings.gradle里有include 'app', 'lib',本阶段会扫描并识别所有子项目。

速记口诀

“定位目录,扫描settings”


3. 项目加载阶段(Project Loading)

作用

  • 创建所有Project对象,形成项目树,但不执行build.gradle内容。

关键方法与内部逻辑

步骤 关键类/方法 说明
1 ProjectFactory.createProject() 创建Project实例
2 ProjectRegistry.addProject() 注册所有Project

源码片段

// org.gradle.api.internal.project.ProjectFactory
public Project createProject(...) {
    // new DefaultProject(...)
    // 仅创建对象,不执行build.gradle
}

场景实例

  • 你的项目有rootapplib三个子工程,这一步只创建这三个Project对象。

速记口诀

“树立项目,尚未配置”


4. 配置阶段(Configuration)

作用

  • 依次执行每个build.gradle,配置插件、任务、依赖等。

关键方法与内部逻辑

步骤 关键类/方法 说明
1 Project.evaluate() 执行build.gradle
2 ScriptHandler.applyScripts() 应用插件和脚本
3 Project.afterEvaluate() 配置后钩子

源码片段

// org.gradle.api.internal.project.DefaultProject
public void evaluate() {
    scriptHandler.applyScripts(); // 执行build.gradle
    // 处理afterEvaluate等钩子
}

场景实例

  • 你在build.gradle里写了apply plugin: 'java'dependencies {}等,这一步会被执行。

速记口诀

“脚本配置,任务齐备”


5. 执行阶段(Execution)

作用

  • 解析用户请求的任务,构建依赖图,执行各个任务。

关键方法与内部逻辑

步骤 关键类/方法 说明
1 TaskGraphExecuter.populate() 构建任务依赖图
2 TaskGraphExecutor.execute() 顺序执行任务
3 Task.execute() 执行任务本身

源码片段

// org.gradle.execution.taskgraph.DefaultTaskGraphExecuter
public void populate() {
    // 递归分析依赖,形成有向无环图
}
public void execute(TaskExecutionGraphInternal graph) {
    for (Task task : graph.getAllTasks()) {
        task.execute();
    }
}

场景实例

  • 你执行gradle build,会自动先执行compileJavaprocessResources等依赖任务。
  • 你自定义了task hello { doLast { println 'Hello, Gradle!' } },执行gradle hello时,这段代码会在task.execute()时被执行。

速记口诀

“依赖成图,顺序执行”


全流程流程图

┌──────────────┐
│ 启动阶段     │
│ 解析命令行   │
└─────┬────────┘
      ▼
┌──────────────┐
│ 初始化阶段   │
│ 加载settings │
└─────┬────────┘
      ▼
┌──────────────┐
│ 项目加载阶段 │
│ 创建Project  │
└─────┬────────┘
      ▼
┌──────────────┐
│ 配置阶段     │
│ 执行build    │
└─────┬────────┘
      ▼
┌──────────────┐
│ 执行阶段     │
│ 执行任务     │
└──────────────┘

源码行级剖析举例(以执行自定义hello任务为例)

假设你的build.gradle有:

task hello {
    doLast {
        println 'Hello, Gradle!'
    }
}
  1. 配置阶段
    • Project.evaluate() 解析build.gradle,通过doLast添加了一个Actionhello任务。
  2. 执行阶段
    • TaskGraphExecutor.execute()遍历到hello任务。
    • hello.execute()时,遍历actions,执行doLast块。
    • 最终输出Hello, Gradle!

对应源码(简化):

// org.gradle.api.internal.AbstractTask
public void execute() {
    for (Action<? super Task> action : actions) {
        action.execute(this); // 调用doLast代码块
    }
}

总结五环节速记口诀

“命令启动,定位设定,树立项目,脚本配置,依赖成图,顺序执行”

启动命令行,初始化定位settings,加载项目树,配置build脚本,构建依赖图,执行各任务。


参考表格

阶段 关键方法/类 内部逻辑 场景/实例 口诀
启动 WrapperMain, GradleMain 解析命令行/守护进程 ./gradlew build 命令启动
初始化 SettingsLoader 加载settings 识别多项目/单项目 定位设定
项目加载 ProjectFactory, ProjectRegistry 创建Project树 root/app/lib项目对象创建 树立项目
配置 Project.evaluate, ScriptHandler 执行build.gradle 插件、任务、依赖定义 脚本配置
执行 TaskGraphExecuter, TaskExecutor 构建依赖图并执行任务 任务执行、doFirst/doLast 依赖成图,顺序执行

进一步剖析Gradle五大环节的更深源码细节,包括关键对象的创建、重要接口的调用、内部状态的变化、典型设计模式、核心数据结构、生命周期钩子等。每一环节都包含源码行级说明,让你把握Gradle底层实现。


1. 启动阶段(Startup)

1.1 关键源码路径

  • org.gradle.wrapper.GradleWrapperMain
  • org.gradle.launcher.GradleMain
  • org.gradle.launcher.daemon.client.DaemonClient
  • org.gradle.launcher.cli.CommandLineActionFactory

1.2 深层细节

a. Wrapper启动与Bootstrap

// wrapper主入口
public static void main(String[] args) {
    File gradleHome = // 解析wrapper配置
    // 构造并调用GradleMain
    GradleMain.main(args);
}

b. 命令行参数解析

// org.gradle.launcher.cli.CommandLineActionFactory
public Action<ExecutionContext> convert(String[] args) {
    // 解析参数到StartParameter对象
    StartParameter parameter = new CommandLineParser().parse(args);
    // 根据参数决定是help、tasks、build等
}

c. 守护进程选择与启动

// org.gradle.launcher.daemon.client.DaemonClient
public void execute() {
    // 检查是否已有Daemon进程
    // 若无则fork新进程,启动DaemonMain
    // 通过Socket通信传递参数
}

深度说明

  • StartParameter是Gradle CLI参数的核心数据结构,贯穿后续所有阶段。
  • 守护进程机制通过Socket和JVM进程池提升性能,守护进程生命周期由org.gradle.launcher.daemon.server.DaemonStateCoordinator管理。

2. 初始化阶段(Initialization)

2.1 关键源码路径

  • org.gradle.initialization.SettingsLoader
  • org.gradle.initialization.DefaultGradleSettingsProcessor
  • org.gradle.initialization.DefaultProjectDescriptor

2.2 深层细节

a. 定位settings.gradle

// org.gradle.initialization.SettingsLoader
public SettingsInternal findAndLoadSettings() {
    File currentDir = startParameter.getCurrentDir();
    File settingsFile = findSettingsFile(currentDir);
    // 递归向上查找settings.gradle文件
    // 若未找到,抛出异常或使用默认配置
}

b. 解析settings.gradle内容

// org.gradle.initialization.DefaultGradleSettingsProcessor
public SettingsInternal process() {
    // 用GroovyShell解析settings.gradle
    // 运行include('subproject')等方法
    // 生成ProjectDescriptor树
}

c. 构建ProjectDescriptor树

// org.gradle.initialization.DefaultProjectDescriptor
public void addProject(String path, File dir) {
    ProjectDescriptor descriptor = new DefaultProjectDescriptor(this, path, dir, ...);
    children.put(path, descriptor);
}

深度说明

  • ProjectDescriptor是项目结构的中间态,后续阶段将转为Project对象。
  • settings.gradle解析用到Groovy DSL,内部通过AST和反射实现动态方法调用。

3. 项目加载阶段(Project Loading)

3.1 关键源码路径

  • org.gradle.api.internal.project.ProjectFactory
  • org.gradle.api.internal.project.DefaultProject
  • org.gradle.internal.service.DefaultServiceRegistry

3.2 深层细节

a. 创建Project对象

// org.gradle.api.internal.project.ProjectFactory
public Project createProject(String name, File projectDir, Project parent, ...) {
    // 依赖注入ServiceRegistry,构造DefaultProject
    return new DefaultProject(name, projectDir, parent, ...);
}

b. ServiceRegistry依赖注入

// org.gradle.internal.service.DefaultServiceRegistry
public <T> T get(Class<T> serviceType) {
    // 延迟加载、单例缓存
    // 用于插件、脚本等依赖注入
}

c. 构建项目树

// org.gradle.api.internal.project.ProjectRegistry
public void addProject(Project project) {
    projectsByPath.put(project.getPath(), project);
    rootProject.addChild(project);
}

深度说明

  • ServiceRegistry是Gradle的核心IoC容器,所有插件、脚本、项目依赖通过它获取。
  • 项目对象树形成后,build.gradle尚未被执行,仅有结构。

4. 配置阶段(Configuration)

4.1 关键源码路径

  • org.gradle.api.internal.project.DefaultProject
  • org.gradle.groovy.scripts.ScriptSource
  • org.gradle.plugin.use.internal.PluginRequestApplicator

4.2 深层细节

a. 执行build.gradle脚本

// org.gradle.api.internal.project.DefaultProject
public void evaluate() {
    // 1. 解析build.gradle为Script对象
    Script script = scriptSource.getScript();
    // 2. 绑定Project为脚本Delegate
    script.setDelegate(this);
    // 3. 执行脚本(Groovy动态调用)
    script.run();
}

b. 插件应用机制

// org.gradle.plugin.use.internal.PluginRequestApplicator
public void applyPlugins(Project project) {
    // 解析plugins {} DSL,下载并加载插件
    // 插件通过ServiceRegistry注入依赖
}

c. 任务与依赖的配置

// build.gradle
task hello {
    doLast {
        println 'Hello, Gradle!'
    }
}
// 实际为:project.getTasks().create('hello').doLast {...}

d. afterEvaluate钩子

// org.gradle.api.internal.project.DefaultProject
public void afterEvaluate(Action<Project> action) {
    // 注册配置后回调
    afterEvaluateActions.add(action);
}

深度说明

  • Groovy脚本执行时,所有DSL调用最终是对Project对象的方法动态调用(Groovy MetaClass)。
  • 插件机制支持本地和远程二进制插件,加载在独立ClassLoader,避免类冲突。

5. 执行阶段(Execution)

5.1 关键源码路径

  • org.gradle.execution.taskgraph.DefaultTaskGraphExecuter
  • org.gradle.execution.taskgraph.DefaultTaskGraphExecutor
  • org.gradle.api.internal.AbstractTask

5.2 深层细节

a. 构建任务依赖有向无环图(DAG)

// org.gradle.execution.taskgraph.DefaultTaskGraphExecuter
public void populate() {
    // 1. 用户请求的任务如build
    // 2. 递归收集所有依赖任务
    // 3. 拓扑排序,形成执行序列
}

b. 任务执行调度与生命周期

// org.gradle.execution.taskgraph.DefaultTaskGraphExecutor
public void execute(TaskExecutionGraphInternal graph) {
    for (Task task : graph.getAllTasks()) {
        task.execute();
    }
}

c. 任务执行(以JavaCompile为例)

// org.gradle.api.tasks.compile.JavaCompile
@Override
public void compile(JavaCompileSpec spec) {
    // 调用Javac编译,参数由build.gradle配置
    compiler.execute(spec);
}

d. 任务钩子与Action执行

// org.gradle.api.internal.AbstractTask
public void execute() {
    // doFirst actions
    for (Action<? super Task> action : doFirstActions) { action.execute(this); }
    // 主体actions
    for (Action<? super Task> action : actions) { action.execute(this); }
    // doLast actions
    for (Action<? super Task> action : doLastActions) { action.execute(this); }
}

e. 任务缓存与增量构建

// org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter
public void execute(TaskInternal task, TaskStateInternal state, ...) {
    if (isUpToDate(task)) {
        state.setSkipped(SkipMessage.UP_TO_DATE);
        return;
    }
    // 否则正常执行
}

深度说明

  • 任务依赖图用DAG存储,保证无循环依赖。
  • 任务生命周期分为doFirst、主action、doLast;可以通过task.doFirst{}task.doLast{}注册。
  • 增量构建通过输入输出快照判断是否需要执行,极大提升性能。

总结流程图(源码对象视角)

┌───────────────┐
│ GradleWrapper │
│ GradleMain    │
└──────┬────────┘
       │
┌──────▼────────┐
│ SettingsLoader│
│ Settings      │
└──────┬────────┘
       │
┌──────▼────────┐
│ ProjectFactory│
│ Project       │
│ ServiceRegistry
└──────┬────────┘
       │
┌──────▼────────┐
│ ScriptSource  │
│ PluginRequest │
│ DefaultProject│
└──────┬────────┘
       │
┌──────▼────────┐
│ TaskGraph     │
│ TaskExecutor  │
│ JavaCompile   │
│ AbstractTask  │
└───────────────┘

总结口诀(源码深化版)

“参数解析指明路,守护进程优先驻;
settings递归树成型,服务注入项目生;
脚本委托Groovy跑,插件分装类隔离;
依赖成图拓扑序,任务三钩可缓存。”


如需某环节更细的代码实现(如插件ClassLoader机制、任务增量快照算法、守护进程Socket通信细节等),请继续追问!

你可能感兴趣的:(gralde,java,gradle,学习方法)