理想情況下,Groovy 建置腳本看起來很像配置:設定專案的一些屬性、配置相依性、宣告任務等等。該配置基於 Groovy 語言結構。本入門旨在解釋這些結構是什麼,以及 — 最重要的是 — 它們與 Gradle 的 API 文件有何關聯。
Project
物件
由於 Groovy 是一種基於 Java 的物件導向語言,因此其屬性和方法適用於物件。在某些情況下,物件是隱含的 — 特別是在建置腳本的頂層,即未巢狀於 {}
區塊內。
考慮以下建置腳本片段,其中包含一個未限定的屬性和區塊
version = '1.0.0.GA'
configurations {
...
}
version
和 configurations {}
都是 org.gradle.api.Project 的一部分。
此範例反映了每個 Groovy 建置腳本都由 Project
的隱含實例支援。如果您看到未限定的元素,並且不知道它的定義位置,請始終檢查 Project
API 文件,以查看它是否來自那裡。
避免在您的建置腳本中使用 Groovy MetaClass 程式設計技術。Gradle 提供了自己的 API 來新增動態執行階段屬性。 使用 Groovy 特定的元程式設計可能會導致建置在建置之間保留大量記憶體,最終導致 Gradle Daemon 記憶體不足。 |
屬性
<obj>.<name> // Get a property value
<obj>.<name> = <value> // Set a property to a new value
"$<name>" // Embed a property value in a string
"${<obj>.<name>}" // Same as previous (embedded value)
version = '1.0.1'
myCopyTask.description = 'Copies some files'
file("$projectDir/src")
println "Destination: ${myCopyTask.destinationDir}"
屬性表示物件的某種狀態。 =
符號的存在清楚地表明您正在查看屬性。否則,限定名稱 — 它以 <obj>.
開頭 — 且沒有任何其他裝飾也是屬性。
如果名稱未限定,則它可能是以下之一
請注意,外掛程式可以將自己的屬性新增至 Project
物件。API 文件列出了核心外掛程式新增的所有屬性。如果您在尋找屬性來源時遇到困難,請檢查建置使用的外掛程式的文件。
當在您的建置腳本中參考非核心外掛程式新增的專案屬性時,請考慮以 project. 作為前綴 — 這樣可以清楚地表明該屬性屬於專案物件。 |
API 文件中的屬性
Groovy DSL 參考顯示了在您的建置腳本中使用的屬性,但 Javadocs 僅顯示方法。這是因為屬性在幕後是以方法實作的
-
如果存在一個名為
get<PropertyName>
的方法,且該方法沒有引數並傳回與屬性相同的類型,則可以讀取屬性。 -
如果存在一個名為
set<PropertyName>
的方法,且該方法有一個引數,其類型與屬性相同,且傳回類型為void
,則可以修改屬性。
請注意,屬性名稱通常以小寫字母開頭,但該字母在方法名稱中是大寫。因此,getter 方法 getProjectVersion()
對應於屬性 projectVersion
。當名稱以至少兩個大寫字母開頭時,此慣例不適用,在這種情況下,大小寫沒有變化。例如,getRAM()
對應於屬性 RAM
。
project.getVersion()
project.version
project.setVersion('1.0.1')
project.version = '1.0.1'
方法
<obj>.<name>() // Method call with no arguments
<obj>.<name>(<arg>, <arg>) // Method call with multiple arguments
<obj>.<name> <arg>, <arg> // Method call with multiple args (no parentheses)
myCopyTask.include '**/*.xml', '**/*.properties'
ext.resourceSpec = copySpec() // `copySpec()` comes from `Project`
file('src/main/java')
println 'Hello, World!'
方法表示物件的某些行為,儘管 Gradle 也經常使用方法來配置物件的狀態。方法可通過其引數或空括號來識別。請注意,有時需要括號,例如當方法沒有引數時,因此您可能會發現始終使用括號最簡單。
Gradle 有一個慣例,如果方法與基於集合的屬性具有相同的名稱,則該方法會將其值附加到該集合。 |
區塊
區塊也是方法,只是最後一個引數具有特定類型。
<obj>.<name> {
...
}
<obj>.<name>(<arg>, <arg>) {
...
}
plugins {
id 'java-library'
}
configurations {
assets
}
sourceSets {
main {
java {
srcDirs = ['src']
}
}
}
dependencies {
implementation project(':util')
}
區塊是一種一次性配置建置元素多個方面的機制。它們還提供了一種巢狀配置的方式,從而形成了一種結構化資料。
您應該了解區塊的兩個重要方面
-
它們以具有特定簽章的方法實作。
-
它們可以更改未限定方法和屬性的目標(「委派」)。
兩者都基於 Groovy 語言功能,我們將在以下章節中對其進行解釋。
區塊方法簽章
您可以通過方法的簽章,或更具體地說,其引數類型,輕鬆地將方法識別為區塊背後的實作。如果方法對應於區塊
-
它必須至少有一個引數。
-
最後一個引數的類型必須為
groovy.lang.Closure
或 org.gradle.api.Action。
例如,Project.copy(Action) 符合這些要求,因此您可以使用以下語法
copy {
into layout.buildDirectory.dir("tmp")
from 'custom-resources'
}
這引出了一個問題,即 into()
和 from()
如何運作。它們顯然是方法,但您會在 API 文件中的哪個位置找到它們?答案來自於了解物件委派。
委派
關於屬性的章節列出了可以在哪裡找到未限定的屬性。一個常見的位置是在 Project
物件上。但是,在區塊內,這些未限定的屬性和方法還有另一個來源:區塊的委派物件。
為了幫助解釋這個概念,請考慮上一節中的最後一個範例
copy {
into layout.buildDirectory.dir("tmp")
from 'custom-resources'
}
此範例中的所有方法和屬性都是未限定的。您可以在 Project
API 文件中輕鬆找到 copy()
和 layout
,但是 into()
和 from()
呢?這些是針對 copy {}
區塊的委派解析的。該委派的類型是什麼?您需要檢查該 API 文件。
有兩種方法可以確定委派類型,具體取決於區塊方法的簽章
-
對於
Action
引數,請查看類型的參數。在上面的範例中,方法簽章為
copy(Action<? super CopySpec>)
,並且是角括號內的部分告訴您委派類型 — 在本例中為 CopySpec。 -
對於
Closure
引數,文件將在描述中明確說明正在配置的類型或委派的類型(對於同一件事使用不同的術語)。
所有新的 Gradle API 都宣告 Action
引數類型而不是 Closure
,這使得挑選委派類型變得非常容易。即使是較舊的 API 除了舊的 Closure
變體之外,也具有 Action
變體。