Gradle複合構建

本文是邊看Gradle英文文檔邊作的筆記:Chapter 11. Composite builds
建議看的時候動手實驗一下,幫助理解java

什麼是複合構建

簡單地說,Gradle的複合構建就是一個構建包含了其它構建。
Gradle的複合構建跟多項目構建很類似,
惟一的區別是多項目構建引入的是單個project(引入的java依賴可使用),
而複合構建引入的是一個完整的構建(除了引入的java依賴,引入的task也可使用)。web

能夠先看如下代碼示例,有個直觀的區分:微信

多項目構建:app

文件:my-app/build.gradle:

dependencies {
    compile project(':util')
    compile project(':web')    
}
//這裏假設有一個my-app的構建,my-app構建依賴了util工程和web工程。

複合構建:ide

文件:my-app/build.gradle:

dependencies {
    compile "org.sample:util:1.0"
    compile "org.sample:web:1.0"
}
//my-app構建沒有直接依賴util和web。而是聲明瞭對util和web的構建結果(class文件)的依賴

多項目構建和複合構建很是類似,所以比較難區分,我是從兩種構建方式關注點上區分的。函數

  • 多項目構建關注點是:如何組織多個項目,項目之間每每是存在業務邏輯聯繫的。好比一個商城項目包含了前臺部分和後臺管理部分,那能夠分紅兩個子項目來作(fun-shop/front和fun-shop/admin)
  • 複合構建關注點是:如何整合多個獨立的項目,被引入的項目是能夠獨立運行的,但不必定有邏輯聯繫。複合構建就像萬能膠水同樣,能整合獨立的gradle項目進來。再拿上面的商城舉例,若是這個商城項目要引入微信支付,這時公司早就有人寫好了一個獨立的微信支付調用的模塊(就叫awesome-wepay吧,假設人家也是用gradle構建的)。你只須要調用他封裝好的簡單的代碼便可。可是因爲人家的awesome-wepay是一個獨立項目,而不是一開始就屬於你的fun-shop項目(awesome-wepay不是fun-shop的子項目,二者關係是相互獨立的),那這個時候,就須要用Gradle的複合構建功能來引入人家的awesome-wepay到你的fun-shop了。

複合構建適用的場景:微信支付

  • 對多個獨立開發的庫進行組合
  • 對一個複雜的多項目構建進行拆分,拆分紅多個獨立的模塊

被複合構建(my-app)引用的構建(util、web),只會向複合構建提供構建的結果,而配置信息是不會被導入到複合構建中的。gradle

若是被複合構建(my-app)包含的構建(util、web)中有依賴能夠知足複合構建的依賴,會優先採用(util、web)該依賴。ui

Gradle默認會自行決定是否採用引入構建的依賴,可是官方建議最好顯式聲明(11.4, 「Declaring the dependencies substituted by an included build」)idea

複合構建(my-app)能夠直接聲明對包含的構建(util、web)的task的依賴,
可是被包含的構建(util、web)因爲它們是獨立的,
被包含的構建(util、web)不能依賴複合構建(my-app)中的task,
也不能依賴其它被包含的構建的task。

如何聲明覆合構建

首先須要聲明覆合構建的依賴

下面的多個例子演示如何將2個獨立開發的構建組合到一個複合構建裏面。
在例子裏面,my-utils是一個多項目構建,包含了2個java庫的構建(number-utils和string-utils),
而my-app則是一個複合構建,my-app使用了這兩個java庫裏面的函數。
須要注意的是,my-app不是直接依賴my-utils,而是聲明對my-utils的兩個java庫的打包結果的依賴

聲明my-app的依賴項:
my-app/build.gradle

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'

group "org.sample"
version "1.0"

mainClassName = "org.sample.myapp.Main"

dependencies {
    compile "org.sample:number-utils:1.0"//<--依賴number-utils子項目的產出結果
    compile "org.sample:string-utils:1.0"//<--依賴string-utils子項目的產出結果
}

repositories {
    jcenter()
}

方式1:經過gradle命令行的--include-build選項實現複合構建
目錄結構是這樣的:

/samples/compositeBuilds/basic
  |--my-app
         |--build.gradle
         |--src/main/java
  |--my-utils
         |--number-utils
                  |--src/main/java
         |--string-utils
                  |--src/main/java
         |--build.gradle
         |--setting.gradle

在my-app目錄下運行命令行:gradle --include-build ../my-utils run便可實現複合構建
這個命令行意思是:
經過gradle --include-build ../my-utils命令告訴gradle先去執行my-utils的構建,my-utils如無心外會產出兩個java庫的構建,number-utils和string-utils目錄下會出現build目錄,build目錄就是構建的產出結果。
而後,因爲my-app/build.gradle中聲明瞭對number-utils和string-utils產出結果的依賴(就是下面的那部分代碼),因此my-app的構建也能成功執行。

dependencies {
    compile "org.sample:number-utils:1.0"//<--依賴number-utils子項目的產出結果
    compile "org.sample:string-utils:1.0"//<--依賴string-utils子項目的產出結果
}

最後,對my-app執行run任務,即運行my-app的代碼。

方式2:在setting.gradle文件中使用includeBuild語句聲明覆合構建

實現以下:

my-app/build.gradle的配置依舊不變

......
dependencies {
    compile "org.sample:number-utils:1.0"//<--依賴number-utils子項目的產出結果
    compile "org.sample:string-utils:1.0"//<--依賴string-utils子項目的產出結果
}
......

my-app/setting.gradle

rootProject.name = 'my-app'
includeBuild '../my-utils'

方式2-補充:不修改my-app/setting.gradle文件實現複合構建

方式2中經過在my-app/setting.gradle文件中添加includeBuild '../my-utils'配置來引入my-utils構建。
若是有特定場景要求不能修改my-app項目的任何文件該怎麼辦呢?這時能夠採起另外一種方式來實現,創建一個新的構建(即一個目錄),在新構建中引入my-app和my-utils,注意,原來是在my-app中引入my-utils的。

實現以下:

目錄結構是這樣的:

/samples/compositeBuilds/basic
  |--composite
         |--build.gradle
         |--setting.gradle
  |--my-app
         |--build.gradle
         |--src/main/java
  |--my-utils
         |--number-utils
                  |--src/main/java
         |--string-utils
                  |--src/main/java
         |--build.gradle
         |--setting.gradle

composite/setting.gradle:

//在composite構建中引入my-app構建和my-utils構建
rootProject.name='adhoc'
includeBuild '../my-app'
includeBuild '../my-utils'

因爲咱們新建了一個名爲composite的構建來包含my-app構建和my-utils構建,可是composite構建到目前爲止是沒有run任務的(原來的my-app構建中定義了mainClassName = "org.sample.myapp.Main"因此能執行run任務),那該怎麼辦呢?
答案就是咱們在composite構建中定義一個的run任務,把該run任務的執行委派給my-app構建的run任務:
composite/build.gradle:

apply plugin: 'idea'

defaultTasks 'run'

task run {
    //composite構建中定義一個run任務,委派給my-app的run任務
    dependsOn gradle.includedBuild('my-app').task(':run')
}

注意:一個構建須要知足什麼條件才能被複合構建引入?

  • 必需要有settings.gradle文件
  • 構建自己不能是複合構建
  • 構建的rootProject.name屬性不能與其它被引入的構建的該屬性相同
  • 構建的rootProject.name屬性不能與複合構建的最頂層級工程的該屬性相同
  • 構建的rootProject.name屬性不能與複合構建的該屬性相同
相關文章
相關標籤/搜索