理想情況下,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 守護程式記憶體不足。 |
屬性
<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>.
開頭)不帶任何其他裝飾也是屬性。
如果名稱未限定,則可能是下列其中一項
請注意,外掛程式可以將其自己的屬性新增到 專案
物件。 API 文件會列出核心外掛程式新增的所有屬性。如果您難以找出屬性來自何處,請查看建置使用的外掛程式的文件。
在建置指令碼中參照非核心外掛程式新增的專案屬性時,請考慮加上 專案. 前綴,這樣就能清楚地表示該屬性屬於專案物件。
|
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
變體。