03.Gradle原理
Gradle 原理
以 Gradle6.5 源码来分析
Gradle 构建核心流程解析
我们执行一个构建任务的时候,都是执行 ./gradlew assembleDebug
这样的命令,其中的 gradlew 脚本就是整个 gradle 构建的入口,前面的代码基本上就是判断环境,设置变量的,直接看最后一行:
1
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
最后执行的命令基本上如下:
1
exec $JAVA_HOME/bin/java -classpath $APP_HOME/gradle/wrapper/gradle-wrapper.jar org.gradle.wrapper.GradleWrapperMain
基本上可以看到,就是执行了 gradle/wrapper/gradle-wrapper.jar 里的 org.gradle.wrapper.GradleWrapperMain
Gradle Wrapper
- Gradle Wrapper 源码路径:
$HOME/.gradle/wrapper/dists/gradle-6.5-all/src/wrapper/
当我们执行一个 gralde 命令时,便会调用 gradle/wrapper/gradle-wrapper.jar
里面 org.gradle.wrapper.GradleWrapperMain
类的 main
方法,它就是 gradle 的一个入口方法
1
2
3
4
5
6
7
8
9
// GradleWrapperMain
public static void main(String[] args) throws Exception {
// ...
// 1、索引到 gradle-wrapper.properties 文件中配置的 gradle zip 地址,并由此包装成一个WrapperExecutor 实例。
WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile);
// 2、使用 wrapperExecutor 实例的 execute 方法执行 gradle 命令。
wrapperExecutor.execute(args, new Install(logger, new Download(logger, "gradlew", "0"), new PathAssembler(gradleUserHome)), new BootstrapMainStarter());
}
继续看看 wrapperExecutor 的 execute 方法:
1
2
3
4
5
6
7
// WrapperExecutor
public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {
// 1、下载 gradle wrapper 需要的依赖与源码。
File gradleHome = install.createDist(this.config);
// 2、从这里开始执行 gradle 的构建流程。
bootstrapMainStarter.start(args, gradleHome);
}
这里就做了两件事:
- 下载 gradle wrapper 需要的依赖以及源码
其中的 gradle wrapper 版本就是我们在 gradle/wrapper/gradle-wrapper.properties 里配置的 distributionUrl,下载位置就是在 gradle-wrapper.properties 里配置的 distributionPath 和 zipStorePath。zipStorePath 是下载的压缩包位置,distributionPath 是解压后的位置,一般默认的位置就是 HOME/.gradle/wrapper/dists/,在这里就可以找到 gradle wrapper 的内容了。如果创建过多个项目的话,我们在 HOME/.gradle/wrapper/dists/ 里可以看到不同版本的 gradle wrapper,这也说明了我们之前最开始说的,为什么要使用 gradle wrapper 而不是直接在电脑里安装 gradle,就是因为 gradle wrapper 会根据不同的项目下载不同版本的内容,项目彼此之间互不影响。
- 执行 gradle 构建流程 调用 bootstrapMainStarter 的 start 方法从这里开始执行 gradle 的构建流程。其内部最终会依次调用
DefaultGradleLauncher
的getLoadedSettings
、getConfiguredBuild
、executeTasks
与finishBuild
方法,它们对应的状态都定义在 DefaultGradleLauncher 中的 Stage 枚举类中。
顺着 BootstrapMainStarter.start() 往下执行了,中间过程就不看了,比较曲折,对理解整体流程也没什么太大的帮助。最终会运行到 DefaultGradleLauncher.executeTasks(),然后再往下的流程就非常清晰了
- Stage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static enum Stage {
LoadSettings,
Configure,
TaskGraph,
RunTasks {
String getDisplayName() {
return "Build";
}
},
Finished;
private Stage() {
}
String getDisplayName() {
return this.name();
}
}
当调用 SettingsInternal#getLoadedSettings 方法时便开始了加载 Setting.gradle 的流程:
1
2
3
4
5
// DefaultGradleLauncher Gradle6.5
public SettingsInternal getLoadedSettings() {
this.doBuildStages(DefaultGradleLauncher.Stage.LoadSettings);
return this.gradle.getSettings();
}
继续调用了 doBuildStages 方法进行处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// DefaultGradleLauncher Gradle6.5
private void doBuildStages(DefaultGradleLauncher.Stage upTo) {
Preconditions.checkArgument(upTo != DefaultGradleLauncher.Stage.Finished, "Stage.Finished is not supported by doBuildStages.");
try {
// ...
// 当 Stage 是 RunTask 的时候执行。
if (upTo == DefaultGradleLauncher.Stage.RunTasks && this.instantExecution.canExecuteInstantaneously()) {
this.doInstantExecution();
} else {
// 当 Stage 不是 RunTask 的时候执行。 this.doClassicBuildStages(upTo);
}
} catch (Throwable var3) {
this.finishBuild(upTo.getDisplayName(), var3);
}
}
继续调用 doClassicBuildStages 方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// DefaultGradleLauncher Gradle6.5
private void doClassicBuildStages(DefaultGradleLauncher.Stage upTo) {
// 1、当 Stage 为 LoadSettings 时执行 prepareSettings 方法去配置并生成 Setting 实例。
this.prepareSettings();
if (upTo != DefaultGradleLauncher.Stage.LoadSettings) {
// 2、当 Stage 为 Configure 时执行 prepareProjects 方法去配置工程。
this.prepareProjects();
if (upTo != DefaultGradleLauncher.Stage.Configure) {
// 3、当 Stage 为 TaskGraph 时执行 prepareTaskExecution 方法去构建 TaskGraph。
this.prepareTaskExecution();
if (upTo != DefaultGradleLauncher.Stage.TaskGraph) {
// 4、当 Stage 为 RunTasks 时执行 saveTaskGraph 方法 与 runWork 方法保存 TaskGraph 并执行相应的 Tasks。 this.instantExecution.saveTaskGraph();
this.runWork();
}
}
}
}
doClassicBuildStages 方法是个很重要的方法,它对所有的 Stage 任务进行了分发
- 当 Stage 为 LoadSettings 时执行 prepareSettings 方法去配置并生成 Setting 实例
- 当 Stage 为 Configure 时执行 prepareProjects 方法去配置工程
- 当 Stage 为 TaskGraph 时执行 prepareTaskExecution 方法去构建 TaskGraph
- 当 Stage 为 RunTasks 时执行 saveTaskGraph 方法 与 runWork 方法保存 TaskGraph 并执行相应的 Tasks
下面就是各个阶段的分析。
LoadSettings
1
2
3
4
5
6
7
8
9
10
11
// DefaultGradleLauncher
private void prepareSettings() {
if (stage == null) {
// 1、回调 BuildListener.buildStarted() 回调接口。
buildListener.buildStarted(gradle);
// 2、调用 settingPreparer 接口的实现类 DefaultSettingsPreparer 的 prepareSettings 方法。
settingsPreparer.prepareSettings(gradle);
// 当前stage状态置为LoadSettings
stage = Stage.LoadSettings;
}
}
在 DefaultGradleLauncher#prepareSettings 方法做了两件事:
- 回调 BuildListener.buildStarted 接口
- 调用 settingPreparer 接口的实现类 DefaultSettingsPreparer 的 prepareSettings 方法。
继续看到 DefaultSettingsPreparer 的 prepareSettings 方法:
1
2
3
4
5
6
7
8
9
@Override
// DefaultSettingsPreparer
public void prepareSettings(GradleInternal gradle) {
// Evaluate init scripts // 1. 执行 init.gradle,它会在每个项目 build 之前被调用,用于做一些初始化的操作。
initScriptHandler.executeScripts(gradle);
// Build `buildSrc`, load settings.gradle, and construct composite (if appropriate) // 2. 调用 SettingLoader 接口的实现类 DefaultSettingsLoader 的 findAndLoadSettings 找到 Settings.gradle 文件的位置。
SettingsLoader settingsLoader = gradle.isRootBuild() ? settingsLoaderFactory.forTopLevelBuild() : settingsLoaderFactory.forNestedBuild();
settingsLoader.findAndLoadSettings(gradle);
}
在 DefaultSettingsPreparer#prepareSettings
方法中做了两项处理
- 执行 init.gradle,它会在每个项目 build 之前被调用,用于做一些初始化的操作
- 调用 SettingLoader 接口的实现类 DefaultSettingsLoader 的 findAndLoadSettings 找到 Settings.gradle 文件的位置
DefaultSettingLoader 的 findAndLoadSettings 方法关联的实现代码非常多,限于篇幅,我这里直接点出 findAndLoadSettings 方法中的主要处理流程:
- 查找 settings.gradle 位置
- 编译 buildSrc(Android 默认的 Plugin 目录)文件夹下的内容
- 解析 gradle.properties 文件:这里会读取 gradle.properties 文件里的配置信息与命令行传入的配置属性并存储
- 解析 settings.gradle 文件:这里最后会调用 BuildOperationScriptPlugin.apply 去执行 settings.gradle 文件。
- 根据 settings.gradle 文件中获得的信息去创建 project 以及 subproject 实例
初始化 init.gradle
初始化 init.gradle 代码路径:
1
DefaultSettingsPreparer#prepareSettings → InitScriptHandler#executeScripts
查找 settings.gradle 位置
1
2
3
4
5
6
7
// DefaultSettingsLoader
public SettingsInternal findAndLoadSettings(GradleInternal gradle) {
// ...
SettingsLocation settingsLocation = buildLayoutFactory.getLayoutFor(new BuildLayoutConfiguration(startParameter));
loadGradlePropertiesFrom(settingsLocation);
// ...
}
现在看 BuildLayoutFactory#getLayoutFor
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// BuildLayoutFactory
public BuildLayout getLayoutFor(BuildLayoutConfiguration configuration) {
if (configuration.isUseEmptySettings()) {
return buildLayoutFrom(configuration, null);
}
File explicitSettingsFile = configuration.getSettingsFile();
if (explicitSettingsFile != null) {
if (!explicitSettingsFile.isFile()) {
throw new MissingResourceException(explicitSettingsFile.toURI(), String.format("Could not read settings file '%s' as it does not exist.", explicitSettingsFile.getAbsolutePath()));
}
return buildLayoutFrom(configuration, explicitSettingsFile);
}
File currentDir = configuration.getCurrentDir();
boolean searchUpwards = configuration.isSearchUpwards();
return getLayoutFor(currentDir, searchUpwards ? null : currentDir.getParentFile());
}
在 getLayoutFor 里,查找 settings.gradle 文件逻辑如下:
- 如果参数里通过 -c xxx.gradle 指定了 settings.gradle 文件的位置,那么直接使用指定的 settings.gradle 文件
- 如果没有指定 settings 文件,就在当前目录下查找
- 如果当前目录没有,会一直往上级目录查找,以及同级的 maseter/ 目录下查找
- 如果都没有找到,还是默认在当前目录下
编译 buildSrc 文件夹下的内容,buildSrc 可以看作插件类似的功能
解析 gradle.properties
解析 settings.gradle
创建 project 以及 subproject
Configure
当执行完 LoadSetting 阶段之后,就会执行 Configure 阶段,而配置阶段所作的事情就是 把 gradle 脚本编译成 class 文件并执行
1
2
3
4
5
6
7
8
// DefaultGradleLauncher
private void prepareProjects() {
// 1、调用 ProjectsPreparer 接口的实现类DefaultProjectsPreparer的prepareProjects()方法。
if (stage == Stage.LoadSettings) {
projectsPreparer.prepareProjects(gradle);
stage = Stage.Configure;
}
}
继续看 DefaultProjectsPreparer#prepareProjects()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// DefaultProjectsPreparer
public void prepareProjects(GradleInternal gradle) {
// 1、如果在 gradle.properties 文件中指定了参数 configure-on-demand,则只会配置主项目以及执行 task 所需要的项目。
if (gradle.getStartParameter().isConfigureOnDemand()) {
IncubationLogger.incubatingFeatureUsed("Configuration on demand");
projectConfigurer.configure(gradle.getRootProject());
} else {
// // 2、如果没有指定在 gradle.properties 文件中指定参数 configure-on-demand,则会调用 ProjectConfigurer 接口的实现类 TaskPathProjectEvaluator 的 configureHierarchy 方法去配置所有项目。
projectConfigurer.configureHierarchy(gradle.getRootProject());
new ProjectsEvaluatedNotifier(buildOperationExecutor).notify(gradle);
}
modelConfigurationListener.onConfigure(gradle);
}
public void configureHierarchy(ProjectInternal project) {
this.configure(project);
Iterator var2 = project.getSubprojects().iterator();
while(var2.hasNext()) {
Project sub = (Project)var2.next();
this.configure((ProjectInternal)sub);
}
}
可以看到在 configureHierarchy 方法中使用了 Iterator 遍历并配置了所有 Project。而 configure 方法最终会调用到 EvaluateProject 类的 run 方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// LifecycleProjectEvaluator.EvaluateProject
public void run(final BuildOperationContext context) {
this.project.getMutationState().withMutableState(new Runnable() {
public void run() {
try {
EvaluateProject.this.state.toBeforeEvaluate();
// 1、 回调 ProjectEvaluationListener 的 beforeEvaluate 接口。
LifecycleProjectEvaluator.this.buildOperationExecutor.run(new LifecycleProjectEvaluator.NotifyBeforeEvaluate(EvaluateProject.this.project, EvaluateProject.this.state));
if (!EvaluateProject.this.state.hasFailure()) {
EvaluateProject.this.state.toEvaluate();
try {
// 2、在 evaluate 方法中会设置默认的 init、wrapper task 和 默认插件,然后便会编译、执行 build.gradle 脚本
LifecycleProjectEvaluator.this.delegate.evaluate(EvaluateProject.this.project, EvaluateProject.this.state);
} catch (Exception var10) {
LifecycleProjectEvaluator.addConfigurationFailure(EvaluateProject.this.project, EvaluateProject.this.state, var10, context);
} finally {
EvaluateProject.this.state.toAfterEvaluate();
// 3、回调 ProjectEvaluationListener.afterEvaluate 接口。
LifecycleProjectEvaluator.this.buildOperationExecutor.run(new LifecycleProjectEvaluator.NotifyAfterEvaluate(EvaluateProject.this.project, EvaluateProject.this.state));
}
}
if (EvaluateProject.this.state.hasFailure()) {
EvaluateProject.this.state.rethrowFailure();
} else {
context.setResult(ConfigureProjectBuildOperationType.RESULT);
}
} finally {
EvaluateProject.this.state.configured();
}
}
});
}
在 EvaluateProject 的 run 方法中有如下 三个重要的处理:
- 回调 ProjectEvaluationListener 的 beforeEvaluate 接口
- 在 evaluate 方法中会设置默认的 init、wrapper task 和 默认插件,然后便会编译并执行 build.gradle 脚本。
- 回调 ProjectEvaluationListener.afterEvaluate 接口。
TaskGraph
执行完 初始化阶段 与 配置阶段 之后,就会 调用到 DefaultGradleLauncher 的 prepareTaskExecution
方法去创建一个由 Tasks 组成的一个有向无环图。
1
2
3
4
5
6
7
private void prepareTaskExecution() {
if (this.stage == DefaultGradleLauncher.Stage.Configure) {
// 1、调用 TaskExecutionPreparer 接口的实现类 BuildOperatingFiringTaskExecutionPreparer 的 prepareForTaskExecution 方法。
this.taskExecutionPreparer.prepareForTaskExecution(this.gradle);
this.stage = DefaultGradleLauncher.Stage.TaskGraph;
}
}
这里继续调用了 TaskExecutionPreparer 接口的实现类 BuildOperatingFiringTaskExecutionPreparer 的 prepareForTaskExecution 方法
1
2
3
public void prepareForTaskExecution(GradleInternal gradle) {
this.buildOperationExecutor.run(new BuildOperatingFiringTaskExecutionPreparer.CalculateTaskGraph(gradle));
}
可以看到,这里使用 buildOperationExecutor 实例执行了 CalculateTaskGraph 这个构建操作,我们看到它的 run 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void run(BuildOperationContext buildOperationContext) {
// 1、填充任务图
final TaskExecutionGraphInternal taskGraph = this.populateTaskGraph();
buildOperationContext.setResult(new Result() {
getRequestedTaskPaths() {
return this.toTaskPaths(taskGraph.getRequestedTasks());
}
public List<String> getExcludedTaskPaths() {
return this.toTaskPaths(taskGraph.getFilteredTasks());
}
private List<String> toTaskPaths(Set<Task> tasks) {
return ImmutableSortedSet.copyOf(Collections2.transform(tasks, new Function<Task, String>() {
public String apply(Task task) {
return task.getPath();
}
})).asList();
}
});
}
直接调用了 populateTaskGraph 填充了 Tasks 有向无环图
1
2
3
4
5
TaskExecutionGraphInternal populateTaskGraph() {
// 1、这里又调用了 TaskExecutionPreparer 接口的另一个实现类 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法。
BuildOperatingFiringTaskExecutionPreparer.this.delegate.prepareForTaskExecution(this.gradle);
return this.gradle.getTaskGraph();
}
可以看到,在注释 1 处,又调用了 TaskExecutionPreparer 接口的另一个实现类 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法
1
2
3
4
5
6
7
8
9
10
11
public void prepareForTaskExecution(GradleInternal gradle) {
// 1
this.buildConfigurationActionExecuter.select(gradle);
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
// 2、根据 Tasks 与 Tasks 间的依赖信息填充 taskGraph 实例。
taskGraph.populate();
this.includedBuildControllers.populateTaskGraphs();
if (gradle.getStartParameter().isConfigureOnDemand()) {
(new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
}
}
1 处调用了 buildConfigurationActionExecuter 接口的 select 方法,这里采用了 策略 + 接口隔离 设计模式,后续会依次调用 ExcludedTaskFilteringBuildConfigurationAction 的 configure 方法、 DefaultTasksBuildExecutionAction 的 configure 方法、TaskNameResolvingBuildConfigurationAction 的 configure 方法
ExcludedTaskFilteringBuildConfigurationAction#configure:处理需要排除的 task
DefaultTasksBuildExecutionAction#configure:添加默认的 task
TaskNameResolvingBuildConfigurationAction#configure:计算 task 依赖图
填充 task 依赖图
RunTasks
1
2
3
4
5
// DefaultGradleLauncher
public GradleInternal executeTasks() {
this.doBuildStages(DefaultGradleLauncher.Stage.RunTasks);
return this.gradle;
}
Ref
- 【灵魂七问】深度探索 Gradle 自动化构建技术(五、Gradle 插件架构实现原理剖析 — 上)
https://juejin.cn/post/6844904142725447687 - 【Android 修炼手册】Gradle 篇 – Gradle 源码分析
https://juejin.cn/post/6844903858641043463