Gradle構(gòu)建的生命周期和其對(duì)象的理解

文章主題內(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è)不同的階段

  1. 初始化(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文件)

  2. 安裝(Configuration)

    在這個(gè)階段,Project對(duì)象被安裝(個(gè)人猜測是執(zhí)行Project對(duì)象的構(gòu)造函數(shù))宁玫。所有參與到這次構(gòu)建的build.gradle腳本文件都會(huì)被執(zhí)行粗恢。

  3. 執(zhí)行(Execution)

    在此階段,gradle將會(huì)決定在安裝(Configuration)階段所創(chuàng)建和裝配的tasks的哪些子集tasks要被執(zhí)行欧瘪。被執(zhí)行的那些task是通過gradle命令的參數(shù)中的task的名字和當(dāng)前在哪個(gè)目錄下來決定的眷射。gradle然后執(zhí)行每一個(gè)被選中的task。

settings.gradle

  1. 除了build.gradle腳本之外佛掖,gradle還定義了一個(gè)settings.gradle文件妖碉。這個(gè)文件會(huì)在初始化(initialization)階段被執(zhí)行。
  2. 一個(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í)打印的情況

  1. settings.gradle文件

    println('initialization:settings.gradle被執(zhí)行')
    
  2. 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'
    }
    
  3. $ 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
    
  4. $ 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
    
  5. $ 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
    
  6. $ 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é)論

  1. 初始化階段執(zhí)行settings.gradle腳本中的內(nèi)容匹中,

  2. 安裝階段執(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ì)象的屬性刹勃,可以直接使用了。

  3. 執(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è)Actionexecute(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é):

  1. 在執(zhí)行build.gradle之前绿鸣,他所對(duì)應(yīng)的Project對(duì)象已然創(chuàng)建,猜測是在執(zhí)行settings.gradle時(shí)已經(jīng)創(chuàng)建了暂氯。
  2. build.gradle中的所有代碼潮模,都作為Project對(duì)象的構(gòu)造函數(shù)一部分而插入構(gòu)造函數(shù)。
  3. 在build.gradle腳本中創(chuàng)建的所有Task對(duì)象都在創(chuàng)建后都被Project對(duì)象的TaskContainer這個(gè)容器對(duì)象引用痴施。
  4. 命令行每執(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é)束。
  5. 當(dāng)直接執(zhí)行g(shù)radle命令而不加task卡骂,也會(huì)依然會(huì)執(zhí)行build.gradle中為Project裝配而存在的代碼国裳,即此時(shí)Project對(duì)象存在,但是只是不去execute task了全跨。

以上缝左,為總結(jié)和對(duì)gradle運(yùn)行原理的猜想,待考證更多資料后證實(shí)之。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渺杉,一起剝皮案震驚了整個(gè)濱河市蛇数,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌是越,老刑警劉巖耳舅,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異倚评,居然都是意外死亡浦徊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門天梧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盔性,“玉大人,你說我怎么就攤上這事腿倚〈砍觯” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵敷燎,是天一觀的道長暂筝。 經(jīng)常有香客問我,道長硬贯,這世上最難降的妖魔是什么焕襟? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮饭豹,結(jié)果婚禮上鸵赖,老公的妹妹穿的比我還像新娘。我一直安慰自己拄衰,他們只是感情好它褪,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著翘悉,像睡著了一般茫打。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妖混,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天老赤,我揣著相機(jī)與錄音,去河邊找鬼制市。 笑死抬旺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的祥楣。 我是一名探鬼主播开财,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼汉柒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了责鳍?” 一聲冷哼從身側(cè)響起竭翠,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎薇搁,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渡八,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啃洋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屎鳍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宏娄。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖逮壁,靈堂內(nèi)的尸體忽然破棺而出孵坚,到底是詐尸還是另有隱情,我是刑警寧澤窥淆,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布卖宠,位于F島的核電站,受9級(jí)特大地震影響忧饭,放射性物質(zhì)發(fā)生泄漏扛伍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一词裤、第九天 我趴在偏房一處隱蔽的房頂上張望刺洒。 院中可真熱鬧,春花似錦吼砂、人聲如沸逆航。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽因俐。三九已至,卻和暖如春赖瞒,著一層夾襖步出監(jiān)牢的瞬間女揭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工栏饮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吧兔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓袍嬉,卻偏偏與公主長得像境蔼,于是被迫代替她去往敵國和親灶平。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 說明 本文主要從實(shí)現(xiàn)原理和代碼層面介紹Gradle開發(fā)相關(guān)知識(shí)箍土。關(guān)于本文中提到的逢享、Gradle中的基本概念等內(nèi)容,...
    jzj1993閱讀 7,940評(píng)論 1 33
  • 構(gòu)建的生命周期 Gradle項(xiàng)目的構(gòu)建分為三個(gè)階段:初始化吴藻、配置瞒爬、執(zhí)行。參考官方手冊(cè) Build Lifecycl...
    十思葉閱讀 3,089評(píng)論 1 6
  • 應(yīng)用拆分 應(yīng)用拆分原則 應(yīng)用拆分思考 Dobbo 和 SpringCloud Dobbo : 分布式服務(wù)框架沟堡,提供...
    Marlon666閱讀 462評(píng)論 0 0
  • 《班主任》 自從當(dāng)了班主任 找我干啥的都有 回家收核桃的 看病的 買衣服的 買感冒藥的 還有一個(gè) 成天在九月的天氣...
    莉莉郭閱讀 623評(píng)論 0 0
  • 清明節(jié)來看爺爺奶奶侧但,我爺爺?shù)男愿窬褪悄欠N執(zhí)著不肯聽人勸的那種,身上挺多病的航罗,一只眼睛幾乎看不見了禀横,耳朵也怎么聽見腿...
    08e32510824f閱讀 109評(píng)論 0 0