文章主題內(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è)人猜測是執(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 configured
william@localhost:~/IdeaProjects/1$ gradle configured initialization:settings.gradle被執(zhí)行 > Configure project : configuration:build.gradle configuration:task configured configuration:task A configuration:task B
-
$ gradle A
initialization: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 B
initialization: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)建,猜測是在執(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í)之。