文章主題內(nèi)容來自
Gradle官方文檔的Understanding the Build Lifecycler章節(jié)。通讀完該章節(jié),大大加深了我對(duì)task對(duì)象,project對(duì)象,gradle.build腳本和project對(duì)象的關(guān)系等這3個(gè)概念的理解。官方文檔地址:https://docs.gradle.org/current/userguide/build_lifecycle.html#sub:building_the_tree

構(gòu)建的不同階段
一個(gè)gradle的構(gòu)建有3個(gè)不同的階段
-
初始化(Initialization)
Gradle支持單和多project的構(gòu)建。在初始化階段,gradle決定了哪一個(gè)或哪些project將要參與到這次構(gòu)建,并且為每個(gè)project創(chuàng)建一個(gè)
Project對(duì)象。(注意,一個(gè)project對(duì)應(yīng)一個(gè)build.gradle文件) -
安裝(Configuration)
在這個(gè)階段,
Project對(duì)象被安裝(個(gè)人猜測(cè)是執(zhí)行Project對(duì)象的構(gòu)造函數(shù))。所有參與到這次構(gòu)建的build.gradle腳本文件都會(huì)被執(zhí)行。 -
執(zhí)行(Execution)
在此階段,gradle將會(huì)決定在安裝(Configuration)階段所創(chuàng)建和裝配的tasks的哪些子集tasks要被執(zhí)行。被執(zhí)行的那些task是通過
gradle命令的參數(shù)中的task的名字和當(dāng)前在哪個(gè)目錄下來決定的。gradle然后執(zhí)行每一個(gè)被選中的task。
settings.gradle
- 除了
build.gradle腳本之外,gradle還定義了一個(gè)settings.gradle文件。這個(gè)文件會(huì)在初始化(initialization)階段被執(zhí)行。 - 一個(gè)multi-project的構(gòu)建必須有一個(gè)
settings.gradle文件在根目錄。因?yàn)楹笳叨x了哪些project(也就是build.gradle腳本)會(huì)參與到這個(gè)構(gòu)建。當(dāng)然,單project(單個(gè)build.gradle腳本)的情況下,settings.gradle可有可無。
3個(gè)不同階段在構(gòu)建中的執(zhí)行順序
1. 定義了3個(gè)task來分別查看他們執(zhí)行時(shí)打印的情況
-
settings.gradle文件println('initialization:settings.gradle被執(zhí)行') -
build.gradle文件println('configuration:build.gradle') task configured{ println('configuration:task configured') } task A{ println('configuration:task A') doLast{ println '這里執(zhí)行task:A#doLast' } } task B { doFirst{ println '這里執(zhí)行task:B#doFirst' } doLast{ println '這里執(zhí)行task:B#doLast' } println 'configuration:task B' } -
$ gradle configuredwilliam@localhost:~/IdeaProjects/1$ gradle configured initialization:settings.gradle被執(zhí)行 > Configure project : configuration:build.gradle configuration:task configured configuration:task A configuration:task B -
$ gradle Ainitialization:settings.gradle被執(zhí)行 > Configure project : configuration:build.gradle configuration:task configured configuration:task A configuration:task B > Task :A 這里執(zhí)行task:A#doLast -
$ gradle B并被添加到Project對(duì)象的一個(gè)字段TaskContainer tasks中,initialization:settings.gradle被執(zhí)行 > Configure project : configuration:build.gradle configuration:task configured configuration:task A configuration:task B > Task :B 這里執(zhí)行task:B#doFirst 這里執(zhí)行task:B#doLast -
$ gradle A Binitialization:settings.gradle被執(zhí)行 > Configure project : configuration:build.gradle configuration:task configured configuration:task A configuration:task B > Task :A 這里執(zhí)行task:A#doLast > Task :B 這里執(zhí)行task:B#doFirst 這里執(zhí)行task:B#doLast
2. 結(jié)論
初始化階段執(zhí)行settings.gradle腳本中的內(nèi)容,
安裝階段執(zhí)行build.gradle腳本中除了
task.doLast(Closure c)和task.doFirst(Closure c)中的所有內(nèi)容。因?yàn)樵诎惭b階段時(shí),該build.gradle文件對(duì)應(yīng)的Project對(duì)象已經(jīng)創(chuàng)建,此時(shí)安裝階段對(duì)應(yīng)的就是Project對(duì)象執(zhí)行其構(gòu)造方法。而上述代碼中在build.gradle中定義了3個(gè)task,那么在安裝階段,這3個(gè)task就會(huì)被創(chuàng)建為3個(gè)task對(duì)象實(shí)例,并且被加入到Project對(duì)象的TaskContainer容器中,此后,這3個(gè)task實(shí)例就作為Project對(duì)象的屬性,可以直接使用了。-
執(zhí)行階段,根據(jù)輸入的task的名稱和相關(guān)依賴(如果存在),去遍歷執(zhí)行對(duì)應(yīng)的task對(duì)象中
private List<ContextAwareTaskAction> actions=new ArrayList<>();的所有的方法,而當(dāng)我們調(diào)用
doLast或者doFirst都是往那個(gè)ArrayList的頭尾插入由我們傳入的閉包而轉(zhuǎn)化成的Action接口的對(duì)象。而Action接口長這樣:@HasImplicitReceiver public interface Action<T> { void execute(T t); }那么到執(zhí)行階段,這個(gè)task的
Action的容器actions就會(huì)被遍歷并調(diào)用每個(gè)Action的execute(T t)方法。
響應(yīng)build.gradle腳本的生命周期
1. Project的安裝
build.gradle中的內(nèi)容依靠Project對(duì)象的構(gòu)造方法來安裝Project對(duì)象,其中有兩個(gè)回調(diào)暴露給我們,分別是
afterEvalueate(Closure closure)
beforeEvalueate(Closure closure)
它們屬于Project接口中就定義了的方法,因此直接用就行
build.gradle:
afterEvaluate {
if (it.hasProperty('group')) {
println('has group')
it.task('B'){
doLast{
println 'execute B'
}
}
} else {
println('do not have group')
}
}
task A {
println(' configure A')
}
執(zhí)行task B
william@localhost:~/IdeaProjects/1$ gradle B
> Configure project :
configure A
has task A
> Task :B
execute B
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
執(zhí)行結(jié)果如上,Project#afterEvaluated(Closure closure)方法會(huì)在Project對(duì)象全部安裝完之后被調(diào)用,這也是其構(gòu)造方法暴露給客戶端的回調(diào),那么Project對(duì)象的構(gòu)造方法的偽代碼如下:
public ProjectImpl(){
runClosureBeforeEvalueation();//執(zhí)行安裝前的閉包
configureCodeInSript();//安裝
runClosureAfterEvalueation();//執(zhí)行安裝后的閉包
}
2. Task的創(chuàng)建
在一個(gè)task對(duì)象被添加到一個(gè)Project對(duì)象后,可以立刻收到一個(gè)回調(diào)。
用tasks.whenTaskAdded(Closure closure)就可以辦到
build.gradle:
tasks.whenTaskAdded {
println(it.name)
}
task A {
println('configure A')
}
task B {
println 'configure B'
}
執(zhí)行task A
william@localhost:~/IdeaProjects/1$ gradle A
> Configure project :
A
configure A
B
configure B
3.Task的執(zhí)行
gradle.taskGraph.addTaskExecutionListener(new TaskExecutionListener() {
@Override
void beforeExecute(Task task) {
}
@Override
void afterExecute(Task task, TaskState state) {
}
})
gradle.taskGraph.beforeTask {
}
gradle.taskGraph.afterTask {
}
上面的接口的方法和下面的兩個(gè)閉包方法的作用都是一樣的,我認(rèn)為他們相比于Task#doFirst或者Task#doLast方法的優(yōu)點(diǎn)在于,TaskExecutionGraph的這幾個(gè)方法,是為每一個(gè)安裝了的task對(duì)象都插入一段回調(diào),這段回調(diào)在每一個(gè)task執(zhí)行前后被調(diào)用。
個(gè)人總結(jié):
- 在執(zhí)行build.gradle之前,他所對(duì)應(yīng)的
Project對(duì)象已然創(chuàng)建,猜測(cè)是在執(zhí)行settings.gradle時(shí)已經(jīng)創(chuàng)建了。 - build.gradle中的所有代碼,都作為
Project對(duì)象的構(gòu)造函數(shù)一部分而插入構(gòu)造函數(shù)。 - 在build.gradle腳本中創(chuàng)建的所有Task對(duì)象都在創(chuàng)建后都被
Project對(duì)象的TaskContainer這個(gè)容器對(duì)象引用。 - 命令行每執(zhí)行一次gradle命令,就創(chuàng)建一個(gè)程序,從類似java的
main方法開始運(yùn)行。創(chuàng)建Project對(duì)象,執(zhí)行build.gradle腳本來安裝(在他的構(gòu)造方法中),而gradle命令后面跟隨的是task的名字,此時(shí)裝配好Project對(duì)象后,根據(jù)傳入的task的名字來去直接執(zhí)行這個(gè)task。當(dāng)task執(zhí)行完畢輸出結(jié)果后,程序結(jié)束,main()方法結(jié)束。 - 當(dāng)直接執(zhí)行g(shù)radle命令而不加task,也會(huì)依然會(huì)執(zhí)行build.gradle中為
Project裝配而存在的代碼,即此時(shí)Project對(duì)象存在,但是只是不去execute task了。
以上,為總結(jié)和對(duì)gradle運(yùn)行原理的猜想,待考證更多資料后證實(shí)之。