Gradle 深度刨析

基本構建塊

每一個 Gradle 構建都包含三個基本概念:project、task 和 property。
每一個構建包含至少一個 project、一個或多個 task。project 和 task 暴露的屬性能夠用來控制構建。
Gradle 的核心組件直接的依賴關係以下:Gradle 的核心組件直接的依賴關係
在多項目構建中,一個 project 能夠依賴於其餘的 project 。在同一個 project 中一個 task 能夠依賴一個或多個 task。html

Project

org.gradle.api.Project 是主要的與 Gradle 構建文件交換的接口,提供了 Gralde 全部特徵的編程訪問方式(例如tTask的建立以及依賴的管理)。在調用對應API時無需使用 project 變量,由於 Gradle 會默認你使用的是 Project 的實例,java

setDescription("project 描述")//在不顯式使用 project 變量的狀況下設置項目描述
println "項目 $name 的描述:"+ description //在不使用 project 變量的狀況下經過 Groovy 語法來訪問 name 以及  description 屬性 【這兩個屬性都是Project對象的屬性】

輸出以下:shell

coderknock@Sanchan:/mnt/d/Windows/Desktop/LearnGradle/Gradle構建原理$ gradle build
Starting a Gradle Daemon (subsequent builds will be faster)
> Configuring > 0/1 projects > root project > Compiling /mnt/d/Windows/Desktop/LearnGradle/Gradle構建原理/build.gradle i項目 Gradle構建原理 的描述:project 描述
:buildEnvironment

------------------------------------------------------------
Root project - project 描述
------------------------------------------------------------

classpath
No dependencies

BUILD SUCCESSFUL

Total time: 15.786 secs

能夠看到,咱們確實能夠訪問到相關的內容。express

一個 Project 能夠建立新的 Task,添加依賴關係和配置,並應用插件和其餘的構建腳本。編程

生命週期

「build.gradle」 文件與Project 實例是一一對應的。在構建初始化時,Gradle 爲每一個參與到構建過程的項目都建立了一個 Project 對象,操做以下:api

  • 爲構建過程建立一個org.gradle.api.initialization.Settings實例閉包

  • 檢查settings.gradle腳本,若是存在,這對上面建立的Settings實例進行相應的配置app

  • 使用Settings實例做爲配置信息建立Project層次的實例模塊化

  • 最後,循環檢擦每一個相關的項目,若是存在"build.gradle"文件,則根據該文件對項目對應的Project對象進行配置。項目的檢查是橫向進行的,這樣一個項目老是會在其子項目以前進行檢測、配置。這個順序能夠經過調用evaluationDependsOnChildren() 進行修改、或者經過evaluationDependsOn(String)方法添加一個明確的檢查依賴關係單元測試

Tasks(任務)

在默認狀況下,每一個新建立的 Task 都是org.gradle.api.DefaultTask類型。DefaultTask裏全部的屬性都是private的,可是提供了gettersetter。Groovy提供的語法糖能夠直接使用屬性名使用屬性。

一個項目基本上是一個Task對象的集合。每一個Task的執行一起基本的工做,如編譯類文件,或運行單元測試,或壓縮war文件。咱們能夠經過實現org.gradle.api.task.TaskContainer接口的類的名爲create的方法(該方法是一個多重載的方法)來添加Task,例如TaskContainer.create(String),還可使用TaskContainer中的一些方法來查找已經存在的Task,例如TaskCollection.getByName(String)
第一個 Gradle 腳本及簡單命令 的學習中咱們對 Task 就已經有過接觸,而且使用過其中一些較爲重要的功能:任務動做(task action)以及任務依賴(task dependency)。

Task action(任務動做)

任務動做定義了一個任務執行時的最小工做單元,能夠是簡單的輸出,也能夠是諸如編譯等較爲複雜的工做。例如第一個 Gradle 腳本及簡單命令 中的:

task helloworldSort {
    //doLast 就是 Task 中的一個任務動做
    doLast{
        print 'Hello world!'
    }
}
Task dependency(任務依賴)

但一個任務運行時須要先運行另外一個任務,這兩個任務間就須要有任務依賴。例如第一個 Gradle 腳本及簡單命令 中的:

// 任務依賴
yayGradle0.dependsOn startSession
/* 任務執行的順序 startSession -> yayGradle0 -> yayGradle1 -> yayGradle2 -> groupTherapy */
// 任務依賴
task groupTherapy(dependsOn: yayGradle2) << {
    println 'groupTherapy'
}

以上就是任務依賴的兩種使用方法。
下面是 Task 的API:
任務Task

Dependencies(依賴項)

一個項目爲了完成構建工做,一般會有數個依賴。此外,項目一般會產生一系列的其餘項目可使用的工件。這些依賴項按配置分組,能夠從資料庫檢出或上傳本身的依賴項到資料庫。getConfigurations()方法返回的ConfigurationContainer用於管理配置相關信息。 getDependencies()方法返回的DependencyHandler用來管理依賴項相關信息。 ArtifactHandler.getArtifacts()方法返回管理工件相關信息。 getRepositories()方法返回的RepositoryHandler用來管理存儲庫相關信息。

多項目構建(Multi-project Builds)

多項目會被排成的一個層次結構。一個項目有一個名稱以及可以惟一標識該層次結構中的徹底限定的路徑。

插件(Plugins)

插件能夠用於模塊化 以及重用項目配置。可使用PluginAware.apply(java.util.Map)方法,應用插件或經過使用插件腳本塊。

plugins {
     id "org.company.myplugin" version "1.3"
 }

以上就是一個簡單的插件腳本塊。

屬性(Properties)

每一個ProjectTask實例都提供了能夠經過gettersetter方法訪問的屬性。
Gradle 執行項目的構建文件來配置對應的Project實例。任何屬性或您的腳本使用的方法是經過授予關聯的Project對象來實現的。這意味着,你能夠在您的腳本直接使用Project接口上的任何方法和屬性。
例如︰

defaultTasks('some-task')  // Project.defaultTasks()
 reportsDir = file('reports') // Project.file() and the Java Plugin

您也能夠訪問使用該屬性的實例來訪問其屬性,在某些狀況下,這可使腳本更清晰。例如,您可使用project.name來訪問該項目的名稱。
一個項目有 6個屬性 「範圍」用於搜索屬性。您能夠經過構建文件中的名稱或經過調用項目的property(String))方法訪問這些屬性。5個屬性「範圍」是:

  1. Project對象自己。此範圍包括Project實現類聲明的屬性的getter和setter。例如,getRootProject())可做爲rootProject的屬性訪問方式。此範圍的屬性是可讀或可寫的,存在對相應 getter 和 setter 方法。

  2. 項目的額外屬性。每一個項目都維護一個額外屬性的映射,能夠包含任意 名稱 - >值 對。一旦定義,該範圍的屬性是可讀和可寫的。有關詳細信息,請參閱其餘屬性

  3. 經過添加插件將擴展添加到項目中。每一個擴展都是隻讀屬性,與擴展具備相同的名稱。

  4. 經過插件將約定屬性添加到項目中。插件能夠經過項目的Convention對象向項目添加屬性和方法。此範圍的屬性能夠是可讀或可寫的,這取決於約定對象。

  5. 項目的任務。能夠經過使用其名稱做爲屬性名稱來訪問任務。此範圍的屬性是隻讀的。例如,調用的任務compile可做爲compile 屬性訪問。

  6. 繼承自父級項目的擴展屬性和慣例屬性,遞歸到根項目。此做用域的屬性爲只讀。

當讀取屬性時,項目按順序搜索上述範圍,並從其找到屬性的第一個範圍返回值。若是未找到,將拋出異常。查看property(String))更多詳細信息。

編寫屬性時,項目按順序搜索上述範圍,並將其屬性設置在第一個做用域中,該屬性位於其中。若是未找到,將拋出異常。查看setProperty(String, Object))更多詳細信息。

擴展屬性

Gradle對的不少領域模型類提供了特別的屬性支持,在內部,這些屬性以鍵值對的形式存儲。全部擴展的屬性必須經過「ext」命名空間進行定義。一旦擴展的屬性被定義,它能夠直接在全部的對象(在下面的狀況下分別是ProjectTasksubprojects)可用,而且能夠被讀取和更新。只須要在最初宣佈經過命名空間來完成。

project.ext.prop1 = "foo"
ext{
  prop2="test"
}
task doStuff {
     ext.prop3 = "bar"
 }
//下面的方法官方文檔中這樣寫,可是實驗時會報錯  "ext.$({ -> ... })" is a method call expression, but it should be a variable expression at line: 10 column: 28. File: _BuildScript_ @ line 10, column 28.
//subprojects { ext.${prop4} = false }
ext.prop5=23

println prop1 //會正常輸出
println prop2 //會正常輸出

//println prop3 //這樣調用會報錯 Could not get unknown property 'prop3' for root project 'Gradle構建原理' of type org.gradle.api.Project.這也證明了默認使用的是 project 實例
println doStuff.prop3 //會正常輸出
println prop5 //會正常輸出

經過「ext」或經過擁有的對象來讀取擴展的屬性。

ext.isSnapshot = version.endsWith("-SNAPSHOT")
if (isSnapshot) {
     // do snapshot stuff
}

擴展屬性也能夠經過屬性文件來提供。

屬性文件

Gradle 屬性能夠經過在 gradle.properties文件中什麼直接添加到項目中,這個文件位於<USER_HOME>/.gradle(這個路徑能夠配置【配置後以配置後的目錄爲準】,後續教程會說起) 目錄或項目的根目錄下。這些屬性能夠經過 project 實例訪問。

gradle.properties:

projectTestPropValue=D:\Windows\Desktop\LearnGradle\projectTestPropValue
userTestpPopValue=E:\gradle_repo\.gradle\projectTestPropValue

使用示例:

println projectTestPropValue
println userTestpPopValue

若是在項目根目錄及 <USER_HOME>/.gradle 下 gradle.properties 中有相同的屬性的話以 <USER_HOME>/.gradle 中爲準。

聲明屬性的其餘方式

對於擴展屬性以及屬性文件兩種方式外,還有聲明自定義變量及值的方式以及下面這些方式聲明屬性:

  • 項目屬性經過 -P 命令行選項提供:
    運行命令時使用:gradle build -P rootTestPropValue=123

  • 系統屬性經過 -D 命令行選項提供
    運行命令時使用:gradle build -D rootTestPropValue=123

  • 環境屬性經過系統環境變量設置:
    ORG_GRADLE_PROJECT_propertyName=值

動態方法

一個項目有5種方法「範圍」,它搜索方法:

  1. Project對象自己。

  2. 構建文件。該項目搜索在構建文件中聲明的匹配方法。

  3. 插件添加到項目的擴展。每一個擴展可用做接受閉包或Action做爲參數的方法。

  4. 經過插件將約定方法添加到項目中。插件能夠經過項目的Convention對象向項目添加屬性和方法。

  5. 項目的任務。爲每一個任務添加一個方法,使用任務的名稱做爲方法名稱並獲取單個閉包或Action參數。該方法Task.configure(groovy.lang.Closure))

  6. 使用提供的閉包調用關聯任務的方法。例如,若是項目有一個被調用的任務compile,那麼將添加一個方法,並帶有如下簽名:void compile(Closure configureClosure)。

  7. 父項目的方法,遞歸到根項目。

  8. 項目的屬性,其值爲閉包。封閉被視爲一種方法,並使用提供的參數進行調用。該物業的位置如上所述。

下面是 Project 的API:
Project API

下面是 PluginAware 的API:

PluginAware API

相關文章
相關標籤/搜索