目錄
1.1.3.環境變量(Environment variables)
1.2.5.3.守護程序使用多少內存,我可以給它更多空間嗎?
1.自定義執行
1.1.配置構建環境
💡有興趣配置構建緩存以加快構建速度嗎?在此處註冊以參加我們的Build Cache培訓課程,以瞭解頂級工程團隊用來提高構建速度的一些技巧。
Gradle提供了多種機制來配置Gradle本身和特定項目的行爲。以下是使用這些機制的參考。
在配置Gradle行爲時,您可以使用以下方法,以從高到低的優先級順序列出(第一個獲勝):
-
命令行標誌(Command-line flags ),例如
--build-cache
。這些優先於屬性和環境變量。 -
系統屬性(System properties),例如
systemProp.http.proxyHost=somehost.org
存儲在gradle.properties
文件中。 -
Gradle屬性(Gradle properties),例如
org.gradle.caching=true
通常存儲在gradle.properties
項目根目錄或GRADLE_USER_HOME
環境變量中的文件中。 -
環境變量(nvironment variables),例如
GRADLE_OPTS
由執行Gradle的環境派生的。
除了配置構建環境之外,您還可以使用Project屬性(Project properties ),例如配置給定的項目構建 -PreleaseType=final
。
1.1.1.Gradle屬性
Gradle提供了幾個選項,可以輕鬆配置將用於執行構建的Java流程。儘管可以通過GRADLE_OPTS
或JAVA_OPTS
在本地環境中配置這些,但將某些設置(例如JVM內存配置和Java主目錄位置)存儲在版本控制中很有用,以便整個團隊可以在一致的環境中工作。
爲構建建立一致的環境就像將這些設置放入gradle.properties
文件一樣簡單。該配置是所有gradle.properties
文件的組合,但是如果在多個位置配置了一個選項,則第一個將獲勝:
-
系統屬性,例如
-Dgradle.user.home
在命令行上設置。 -
gradle.properties
在GRADLE_USER_HOME
目錄中。 -
gradle.properties
在項目根目錄中。 -
gradle.properties
在Gradle安裝目錄中。
以下屬性可用於配置Gradle構建環境:
org.gradle.caching=(true,false)
- 設置爲true時,Gradle將在可能的情況下重用任何先前構建的任務輸出,從而使構建速度更快。瞭解有關使用構建緩存的更多信息。
org.gradle.caching.debug=(true,false)
- 設置爲true時,單個輸入屬性哈希值和每個任務的構建緩存鍵都記錄在控制檯上。瞭解有關任務輸出緩存的更多信息。
org.gradle.configureondemand=(true,false)
org.gradle.console=(auto,plain,rich,verbose)
- 自定義控制檯輸出的顏色或詳細程度。默認值取決於如何調用Gradle。有關其他詳細信息,請參見命令行日誌記錄。
org.gradle.daemon=(true,false)
- 當設置
true
的Gradle守護進程來運行構建。默認值爲true
。
- 當設置
org.gradle.daemon.idletimeout=(# of idle millis)
- 在指定的空閒毫秒數後,Gradle守護程序將自行終止。默認值爲
10800000
(3小時)。
- 在指定的空閒毫秒數後,Gradle守護程序將自行終止。默認值爲
org.gradle.debug=(true,false)
- 設置
true
爲時,Gradle將在啓用遠程調試的情況下運行構建,偵聽端口5005。請注意,這等同於添加-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
到JVM命令行,並且將掛起虛擬機,直到連接了調試器。默認值爲false
。
- 設置
org.gradle.java.home=(path to JDK home)
- 指定用於Gradle構建過程的Java主頁。可以將值設置爲
jdk
或jre
,但是,根據您的構建方式,使用JDK更安全。如果未指定設置,則從您的環境(JAVA_HOME
或的路徑java
)派生合理的默認值。這不會影響用於啓動Gradle客戶端VM的Java版本(請參閱環境變量)。
- 指定用於Gradle構建過程的Java主頁。可以將值設置爲
org.gradle.jvmargs=(JVM arguments)
- 指定用於Gradle守護程序的JVM參數。該設置對於配置JVM內存設置以提高構建性能特別有用。這不會影響Gradle客戶端VM的JVM設置。
org.gradle.logging.level=(quiet,warn,lifecycle,info,debug)
- 當設置爲quiet, warn, lifecycle, info, debug時,Gradle將使用此日誌級別。這些值不區分大小寫。該
lifecycle
級別是默認級別。請參閱選擇日誌級別。
- 當設置爲quiet, warn, lifecycle, info, debug時,Gradle將使用此日誌級別。這些值不區分大小寫。該
org.gradle.parallel=(true,false)
- 配置後,Gradle將分叉到
org.gradle.workers.max
JVM以並行執行項目。要了解有關並行任務執行的更多信息,請參閱Gradle性能指南。
- 配置後,Gradle將分叉到
org.gradle.warning.mode=(all,fail,summary,none)
- 當設置爲
all
,summary
或者none
,搖籃會使用不同的預警類型的顯示器。有關詳細信息,請參見命令行日誌記錄選項。
- 當設置爲
org.gradle.workers.max=(max # of worker processes)
- 配置後,Gradle將使用最多給定數量的工人。默認值爲CPU處理器數。另請參閱性能命令行選項。
org.gradle.priority=(low,normal)
- 指定Gradle守護程序及其啓動的所有進程的調度優先級。默認值爲
normal
。另請參閱性能命令行選項。
- 指定Gradle守護程序及其啓動的所有進程的調度優先級。默認值爲
下面的示例演示各種屬性的用法。
示例1.使用gradle.properties文件設置屬性
gradle.properties
gradlePropertiesProp=gradlePropertiesValue
sysProp=shouldBeOverWrittenBySysProp
systemProp.system=systemValue
Groovy
build.gradle
task printProps {
doLast {
println commandLineProjectProp
println gradlePropertiesProp
println systemProjectProp
println System.properties['system']
}
}
$ gradle -q -PcommandLineProjectProp=commandLineProjectPropValue -Dorg.gradle.project.systemProjectProp=systemPropertyValue printProps
commandLineProjectPropValue
gradlePropertiesValue
systemPropertyValue
systemValue
Kotlin
build.gradle.kts
// Project properties can be accessed via delegation
val commandLineProjectProp: String by project
val gradlePropertiesProp: String by project
val systemProjectProp: String by project
tasks.register("printProps") {
doLast {
println(commandLineProjectProp)
println(gradlePropertiesProp)
println(systemProjectProp)
println(System.getProperty("system"))
}
}
$ gradle -q -PcommandLineProjectProp=commandLineProjectPropValue -Dorg.gradle.project.systemProjectProp=systemPropertyValue printProps
commandLineProjectPropValue
gradlePropertiesValue
systemPropertyValue
systemValue
1.1.2.系統(System)屬性
使用-D
命令行選項,可以將系統屬性傳遞給運行Gradle的JVM。在-D
該選項的gradle
命令有作爲的效果相同-D
的選項的java
命令。
您還可以在gradle.properties
帶有前綴的文件中設置系統屬性systemProp.
在gradle.properties
中指定系統屬性
systemProp.gradle.wrapperUser=myuser
systemProp.gradle.wrapperPassword=mypassword
以下系統屬性可用。請注意,命令行選項(command-line)優先於系統屬性。
gradle.wrapperUser=(myuser)
- 指定用戶名以使用HTTP基本認證從服務器下載Gradle發行版。在身份驗證的包裝下載中瞭解更多信息。
gradle.wrapperPassword=(mypassword)
- 指定使用Gradle包裝器下載Gradle發行版的密碼。
gradle.user.home=(path to directory)
- 指定Gradle用戶的主目錄。
在多項目構建中,將忽略除根目錄之外的任何項目中設置的“systemProp.
”屬性。也就是說,將僅檢查根項目的gradle.properties
文件中以“systemProp.
”開頭的屬性。
1.1.3.環境變量(Environment variables)
以下環境變量可用於該gradle
命令。請注意,命令行選項(command-line)和系統屬性優先於環境變量。
GRADLE_OPTS
- 指定啓動Gradle客戶端VM時要使用的JVM參數。客戶端VM僅處理命令行輸入/輸出,因此很少需要更改其VM選項。實際的構建由Gradle守護程序運行,不受此環境變量的影響。
GRADLE_USER_HOME
- 指定Gradle用戶的主目錄(
$USER_HOME/.gradle
如果未設置,則默認爲)。
- 指定Gradle用戶的主目錄(
JAVA_HOME
- 指定要用於客戶端VM的JDK安裝目錄。除非使用帶着
org.gradle.java.home配置的
Gradle屬性文件指定了另一個虛擬機,否則此虛擬機也用於守護程序。
- 指定要用於客戶端VM的JDK安裝目錄。除非使用帶着
1.1.4.項目性質
您可以通過命令行選項 -P
將屬性直接添加到 Project 對象。
當Gradle看到特別命名的系統屬性或環境變量時,它也可以設置項目屬性。如果環境變量名稱看起來像ORG_GRADLE_PROJECT_prop=somevalue
,則Gradle將在項目對象上設置一個屬性prop
,值爲somevalue
。Gradle也爲系統屬性支持此功能,但是具有不同的命名模式,看起來像org.gradle.project.prop
。以下兩項都將Project對象上的屬性foo
設置爲"bar"
。
通過系統屬性設置項目屬性
org.gradle.project.foo=bar
通過環境變量設置項目屬性
ORG_GRADLE_PROJECT_foo=bar
✨用戶主目錄中的屬性文件優先於項目目錄中的屬性文件。
當您對連續集成服務器沒有管理員權限並且需要設置不容易看到的屬性值時,此功能非常有用。由於您不能在那種情況下使用該 -P
選項,也不能更改系統級配置文件,因此正確的策略是更改連續集成構建作業的配置,並添加與預期模式匹配的環境變量設置。這對於系統上的普通用戶是不可見的。
您可以像使用變量一樣使用名稱來訪問構建腳本中的項目屬性。
✨如果引用了項目屬性但該屬性不存在,則將引發異常,並且構建將失敗。
在使用Project.hasProperty(java.lang.String)方法訪問可選項目屬性之前,應檢查其是否存在。
1.1.5.配置JVM內存
您可以通過以下方式調整Gradle的JVM選項:
該org.gradle.jvmargs
Gradle屬性控制虛擬機上運行的版本。默認爲-Xmx512m "-XX:MaxMetaspaceSize=256m"
更改構建VM的JVM設置
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
在JAVA_OPTS
環境變量控制命令行客戶機,其僅用於顯示控制檯輸出。默認爲-Xmx64m
更改客戶端VM的JVM設置
JAVA_OPTS="-Xmx64m -XX:MaxPermSize=64m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8"
✨在一種情況下,客戶端VM也可以用作構建VM:如果停用Gradle Daemon,並且客戶端VM具有與構建VM所需的相同設置,則客戶端VM將直接運行構建。否則,客戶端虛擬機將派生一個新的虛擬機來運行實際的構建,以便採用不同的設置。
某些任務(如test
任務)也會派生其他JVM進程。您可以通過任務本身來配置它們。它們-Xmx512m
默認都使用。
示例2.爲JavaCompile任務設置Java編譯選項
Groovy
build.gradle
plugins {
id 'java'
}
tasks.withType(JavaCompile) {
options.compilerArgs += ['-Xdoclint:none', '-Xlint:none', '-nowarn']
}
Kotlin
build.gradle.kts
plugins {
java
}
tasks.withType<JavaCompile>().configureEach {
options.compilerArgs = listOf("-Xdoclint:none", "-Xlint:none", "-nowarn")
}
請參閱Test API文檔中的其他示例,以及Java插件參考中的測試執行。
使用該--scan
選項時,構建掃描將告訴您有關執行構建的JVM的信息。
1.1.6.使用項目屬性配置任務
可以根據調用時指定的項目屬性來更改任務的行爲。
假設您想確保發佈版本僅由CI觸發。一種簡單的處理方法是通過isCI
項目屬性。
例子3.防止釋放到CI外
Groovy
build.gradle
task performRelease {
doLast {
if (project.hasProperty("isCI")) {
println("Performing release actions")
} else {
throw new InvalidUserDataException("Cannot perform release outside of CI")
}
}
}
$ gradle performRelease -PisCI=true --quiet
Performing release actions
Kotlin
build.gradle.kts
tasks.register("performRelease") {
doLast {
if (project.hasProperty("isCI")) {
println("Performing release actions")
} else {
throw InvalidUserDataException("Cannot perform release outside of CI")
}
}
}
$ gradle performRelease -PisCI=true --quiet
Performing release actions
1.1.7.通過HTTP代理訪問網絡
通過標準JVM系統屬性來配置HTTP或HTTPS代理(例如,用於下載依賴項)。這些屬性可以直接在構建腳本中設置。例如,可以使用設置HTTP代理主機System.setProperty('http.proxyHost', 'www.somehost.org')
.。另外,可以在gradle.properties中指定屬性。
使用gradle.properties
配置HTTP代理
systemProp.http.proxyHost=www.somehost.org
systemProp.http.proxyPort=8080
systemProp.http.proxyUser=userid
systemProp.http.proxyPassword=password
systemProp.http.nonProxyHosts=*.nonproxyrepos.com|localhost
HTTPS有單獨的設置。
使用gradle.properties
配置HTTPS代理
systemProp.https.proxyHost=www.somehost.org
systemProp.https.proxyPort=8080
systemProp.https.proxyUser=userid
systemProp.https.proxyPassword=password
systemProp.https.nonProxyHosts=*.nonproxyrepos.com|localhost
您可能需要設置其他屬性才能訪問其他網絡。這裏有2個參考可能會有所幫助:
1.1.8.NTLM身份驗證
如果您的代理服務器需要NTLM身份驗證,則可能需要提供身份驗證域以及用戶名和密碼。您可以通過兩種方式提供用於向NTLM代理進行身份驗證的域:
-
將
http.proxyUser
系統屬性設置爲domain/username
。 -
通過
http.auth.ntlm.domain
system屬性提供身份驗證域。
1.2.Gradle守護程序
守護程序是一種計算機程序,它作爲後臺進程運行,而不是受交互式用戶的直接控制。 —維基百科
Gradle在Java虛擬機(JVM)上運行,並使用幾個支持庫,它們需要很短的初始化時間。結果,有時啓動似乎有些慢。解決此問題的方法是Gradle Daemon:這是一個長期存在的後臺進程,與以前相比,它可以更快地執行構建。通過避免昂貴的引導過程以及利用緩存(將有關項目的數據保留在內存中),我們可以實現這一目標。使用Daemon運行Gradle構建與沒有運行沒有什麼不同。只需配置您是否要使用它-其他所有事情都由Gradle透明地處理。
1.2.1.爲什麼Gradle Daemon對性能很重要
守護進程是一個長期存在的過程,因此我們不僅可以避免每次構建都需要啓動JVM的成本,而且還可以在內存中緩存有關項目結構,文件,任務等的信息。
推理很簡單:通過重用以前構建的計算來提高構建速度。但是,這樣做的好處是巨大的:我們通常會在以後的構建中將構建時間減少15-75%。我們建議您使用 --profile
來對構建進行概要分析,以瞭解Gradle Daemon對您的影響。
默認情況下,Gradle Daemon從Gradle 3.0開始啓用,因此您無需做任何事情就可以從中受益。
1.2.2.運行守護程序狀態
要獲取正在運行的Gradle守護程序及其狀態的列表,請使用 --status
命令。
Sample output:
PID VERSION STATUS
28411 3.0 IDLE
34247 3.0 BUSY
當前,給定的Gradle版本只能連接到相同版本的守護程序。這意味着狀態輸出將僅顯示正在調用的Gradle版本的守護程序,而不顯示任何其他版本的守護程序。Gradle的未來版本將解除此約束,並將顯示所有Gradle版本的正在運行的守護程序。
1.2.3.禁用守護程序
Gradle守護程序默認情況下處於啓用狀態,我們建議始終啓用它。有幾種方法可以禁用守護程序,但是最常見的一種方法是添加該行
org.gradle.daemon=false
到文件«USER_HOME»/.gradle/gradle.properties
,«USER_HOME»
您的主目錄在哪裏。通常是以下之一,具體取決於您的平臺:
C:\Users\<username>
(Windows Vista & 7+)/Users/<username>
(macOS)/home/<username>
(Linux)
如果該文件不存在,請使用文本編輯器創建它。您可以在下面的"Daemon FAQ"找到其他禁用(啓用)守護程序的方法的詳細信息。該部分還包含有關守護程序如何工作的更多詳細信息。
請注意,啓用了守護程序後,無論特定構建使用的Gradle版本如何,所有構建都將利用速度提升。
💡持續集成
從Gradle 3.0開始,我們默認啓用Daemon並建議將其用於開發人員的計算機和Continuous Integration服務器。但是,如果您懷疑Daemon使CI構建不穩定,則可以將其禁用以對每個構建使用全新的運行時,因爲運行時與任何先前的構建完全隔離。
1.2.4.停止現有的守護程序
如前所述,守護進程是一個後臺進程。不過,您不必擔心計算機上會建立Gradle進程。與可用的系統內存總量相比,每個守護程序都會監視其內存使用情況,如果空閒的系統內存不足,則每個空閒進程都會停止運行。如果您出於任何原因要明確停止運行Daemon進程,只需使用命令 gradle --stop
。
這將終止所有與用於執行命令的相同Gradle版本一起啓動的Daemon進程。如果安裝了Java開發工具包(JDK),則可以通過運行 jps
命令輕鬆地驗證守護程序是否已停止。您會看到名稱爲 GradleDaemon
的所有正在運行的守護程序。
1.2.5.常問問題(FAQ)
1.2.5.1.如何禁用Gradle守護程序?
有兩種建議的方法可以持久禁用環境的守護程序:
-
通過環境變量:將標誌添加
-Dorg.gradle.daemon=false
到GRADLE_OPTS
環境變量 -
通過屬性文件:添加
org.gradle.daemon=false
到«GRADLE_USER_HOME»/gradle.properties
文件
✨注意,
«GRADLE_USER_HOME»
默認爲«USER_HOME»/.gradle
,其中«USER_HOME»
是當前用戶的主目錄。可以通過-g
和--gradle-user-home
命令行開關以及GRADLE_USER_HOME
環境變量和org.gradle.user.home
JVM系統屬性來配置此位置。
兩種方法具有相同的效果。使用哪一個取決於個人喜好。大多數Gradle用戶選擇第二個選項,然後將條目添加到用戶gradle.properties
文件中。
在Windows上,此命令將爲當前用戶禁用守護程序:
(if not exist "%USERPROFILE%/.gradle" mkdir "%USERPROFILE%/.gradle") && (echo. >> "%USERPROFILE%/.gradle/gradle.properties" && echo org.gradle.daemon=false >> "%USERPROFILE%/.gradle/gradle.properties")
在類似UNIX的操作系統上,以下Bash shell命令將爲當前用戶禁用守護程序:
mkdir -p ~/.gradle && echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
一旦以此方式爲構建環境禁用了守護程序,除非使用該--daemon
選項明確請求,否則不會啓動Gradle守護程序。
使用Gradle命令行界面時,--daemon
和--no-daemon
命令行選項可啓用和禁用守護程序用於單獨的構建調用。在考慮構建環境時,這些命令行選項具有最高優先級。通常,爲環境(例如,用戶帳戶)啓用守護程序更爲方便,以便所有構建都使用守護程序而無需記住要提供該--daemon
選項。
1.2.5.2.爲什麼我的機器上有多個守護進程?
Gradle爲什麼要創建一個新的守護進程,而不是使用已經運行的守護進程,有幾個原因。基本規則是,如果沒有可用的空閒或兼容守護程序,則Gradle將啓動新的守護程序。Gradle將殺死任何閒置了3個小時或更長時間的守護進程,因此您不必擔心手動清理它們。
idle
空閒的守護程序是當前未執行構建或未執行其他有用工作的守護程序。
compatible
兼容的守護程序是可以(或可以使其)滿足所請求構建環境的要求的守護程序。用於執行構建的Java運行時是構建環境的一個示例方面。另一個示例是構建運行時所需的JVM系統屬性集。
守護程序可能無法滿足請求的構建環境的某些方面。如果守護程序與Java 8運行時一起運行,但是請求的環境要求Java 10,則該守護程序不兼容,必須啓動另一個守護程序。而且,一旦JVM啓動,就無法更改Java運行時的某些屬性。例如,不可能更改-Xmx1024m
正在運行的JVM 的內存分配(例如),默認文本編碼,默認語言環境等。
通常從構建客戶端(例如Gradle命令行客戶端,IDE等)環境的各個方面隱式構建“請求的構建環境”,並通過命令行開關和設置顯式構建“請求的構建環境”。有關如何指定和控制構建環境的詳細信息,請參見構建環境。
以下JVM系統屬性實際上是不可變的。如果請求的構建環境需要這些屬性中的任何一個,且其值與守護程序的JVM具有的該屬性的值不同,則守護程序不兼容。
- file.encoding
- user.language
- user.country
- user.variant
- java.io.tmpdir
- javax.net.ssl.keyStore
- javax.net.ssl.keyStorePassword
- javax.net.ssl.keyStoreType
- javax.net.ssl.trustStore
- javax.net.ssl.trustStorePassword
- javax.net.ssl.trustStoreType
- com.sun.management.jmxremote
由啓動參數控制的以下JVM屬性也實際上是不可變的。爲了使守護程序兼容,請求的構建環境和守護程序的環境的相應屬性必須完全匹配。
-
最大堆大小(即-Xmx JVM參數)
-
最小堆大小(即-Xms JVM參數)
-
引導類路徑(即-Xbootclasspath參數)
-
“assertion”狀態(即-ea參數)
所需的Gradle版本是所請求的構建環境的另一方面。守護進程與特定的Gradle運行時耦合。在使用不同Gradle版本的會話中處理多個Gradle項目是導致多個Daemon進程運行的常見原因。
1.2.5.3.守護程序使用多少內存,我可以給它更多空間嗎?
如果請求的構建環境未指定最大堆大小,則守護程序將使用最多512MB的堆。它將使用JVM的默認最小堆大小。對於大多數構建來說,512MB綽綽有餘。具有數百個子項目的較大內部版本,大量配置和源代碼可能需要或具有更好的性能,並具有更多的內存。
要增加守護程序可以使用的內存量,請在請求的構建環境中指定適當的標誌。有關詳細信息,請參見構建環境。
1.2.5.4.如何停止守護程序?
閒置3個小時或更短的時間後,守護進程將自動終止。如果您希望在此之前停止Daemon進程,則可以通過操作系統終止該進程或運行gradle --stop
命令。該--stop
開關使Gradle請求所有正在運行的,與用於運行命令的Gradle版本相同的Daemon進程自行終止。
1.2.5.5.守護程序會出什麼問題?
在日常開發中,使Daemon健壯,透明且不引人注目的工程已經投入了大量精力。但是,守護進程有時會被破壞或耗盡。Gradle構建從多個源執行任意代碼。雖然Gradle本身是爲Daemon設計並經過嚴格測試的,但用戶構建腳本和第三方插件可能會通過內存泄漏或全局狀態損壞等缺陷破壞Daemon進程的穩定性。
通過運行無法正確釋放資源的構建,還可能破壞守護進程(通常是構建環境)的穩定性。當使用Microsoft Windows時,這是一個特別棘手的問題,因爲它對讀取或寫入後無法關閉文件的程序的寬容度較小。
Gradle主動監視堆使用情況,並嘗試檢測何時泄漏開始耗盡守護程序中的可用堆空間。當檢測到問題時,Gradle守護程序將完成當前正在運行的構建,並在下一個構建中主動重新啓動該守護程序。默認情況下啓用此監視,但是可以通過將org.gradle.daemon.performance.enable-monitoring
system屬性設置爲false 來禁用此監視。
如果懷疑Daemon進程變得不穩定,則可以將其殺死。回想一下,--no-daemon
可以爲構建指定開關,以防止使用守護程序。這對於診斷守護程序是否實際上是問題的元兇很有用。
1.2.6.工具和IDE
IDE和其他工具用於與Gradle集成的Gradle Tooling API 始終使用Gradle守護程序執行構建。如果要在IDE中執行Gradle構建,則使用的是Gradle Daemon,而無需爲您的環境啓用它。
1.2.7.Gradle守護程序如何使構建更快?
Gradle守護程序是一個長期存在的構建過程。在兩次構建之間,它空閒地等待下一次構建。這具有明顯的好處,即對於多個構建只需要一次將Gradle加載到內存中,而不是對於每個構建一次。這本身就是一項重大的性能優化,但並非止於此。
對於現代JVM性能而言,故事的重要部分是運行時代碼優化。例如,HotSpot(Oracle提供的JVM實現,用作OpenJDK的基礎)在運行時對代碼進行優化。優化是漸進的,不是瞬時的。也就是說,在執行過程中對代碼進行了逐步優化,這意味着純粹由於此優化過程而使得後續構建可以更快。使用HotSpot進行的實驗表明,需要5到10次構建才能穩定優化。守護程序的第一個構建和第10個構建之間的可感知構建時間差異可能非常明顯。
守護程序還允許跨構建更有效地進行內存緩存。例如,構建所需的類(例如,插件,構建腳本)可以保存在構建之間的內存中。同樣,Gradle可以維護構建數據的內存緩存,例如用於增量構建的任務輸入和輸出的哈希值。
1.3.初始化腳本
Gradle提供了一種強大的機制,可以根據當前環境自定義構建。該機制還支持希望與Gradle集成的工具。
請注意,這與“build-init
”插件提供的“init
”任務完全不同(請參閱Build Init插件)。
1.3.1.基本用法
初始化(Initialization)腳本(又稱初始化(init )腳本)與Gradle中的其他腳本相似。但是,這些腳本在構建開始之前運行。以下是幾種可能的用途:
-
設置企業範圍的配置,例如在哪裏可以找到自定義插件。
-
根據當前環境設置屬性,例如開發人員的計算機與持續集成服務器。
-
提供構建所需的有關用戶的個人信息,例如存儲庫或數據庫身份驗證憑據。
-
定義機器特定的詳細信息,例如JDK的安裝位置。
-
註冊構建偵聽器。希望監聽Gradle事件的外部工具可能會發現這很有用。
-
註冊構建記錄器。您可能希望自定義Gradle如何記錄它生成的事件。
初始化腳本的一個主要限制是它們不能訪問buildSrc
項目中的類(有關此功能的詳細信息,請參見使用buildSrc提取命令式邏輯)。
1.3.2.使用初始化腳本
有幾種使用初始化腳本的方法:
-
在命令行上指定一個文件。命令行選項位於腳本路徑之後,
-I
或--init-script
位於腳本路徑之後。命令行選項可以多次出現,每次添加另一個初始化腳本。如果命令行上指定的任何文件不存在,則構建將失敗。 -
在目錄中放置一個名爲
init.gradle
(或init.gradle.kts
)USER_HOME/.gradle/
文件。 -
在目錄中放置一個以
.gradle
(或.init.gradle.kts
)結尾的文件USER_HOME/.gradle/init.d/
。 -
在Gradle發行版的目錄中放置一個以
.gradle
(或.init.gradle.kts
)結尾的文件GRADLE_HOME/init.d/
。這使您可以打包包含一些自定義構建邏輯和插件的自定義Gradle發行版。您可以將其與Gradle包裝器結合使用,以使自定義邏輯可用於企業中的所有內部版本。
如果發現一個以上的初始化腳本,它們將全部按照上述指定的順序執行。給定目錄中的腳本按字母順序執行。例如,這允許使用一種工具在命令行上指定一個初始化腳本,並且用戶可以將一個腳本放入其主目錄中以定義環境,並且在執行Gradle時,這兩個腳本都將運行。
1.3.3.編寫一個初始化腳本
類似於Gradle構建腳本,初始化腳本是Groovy或Kotlin腳本。每個初始化腳本都有一個與之關聯的Gradle實例。初始化腳本中的任何屬性引用和方法調用都將委派給該Gradle
實例。
每個初始化腳本還實現腳本接口。
1.3.3.1.通過初始化腳本配置項目
您可以使用初始化腳本來配置構建中的項目。這與在多項目構建中配置項目的方式類似。以下示例顯示了在評估項目之前如何通過初始化腳本執行額外的配置。此樣本使用此功能來配置額外的存儲庫,以僅用於某些環境。
示例1.在評估項目之前,使用init腳本執行額外的配置
Grovvy
build.gradle
repositories {
mavenCentral()
}
task showRepos {
doLast {
println "All repos:"
println repositories.collect { it.name }
}
}
init.gradle
allprojects {
repositories {
mavenLocal()
}
}
Kotlin
build.gradle.kts
repositories {
mavenCentral()
}
tasks.register("showRepos") {
doLast {
println("All repos:")
//TODO:kotlin-dsl remove filter once we're no longer on a kotlin eap
println(repositories.map { it.name }.filter { it != "maven" })
}
}
init.gradle.kts
allprojects {
repositories {
mavenLocal()
}
}
應用初始化腳本時的輸出(Output when applying the init script)
Grovvy
> gradle --init-script init.gradle -q showRepos
All repos:
[MavenLocal, MavenRepo]
Kotlin
> gradle --init-script init.gradle.kts -q showRepos
All repos:
[MavenLocal, MavenRepo]
1.3.4.初始化腳本的外部依賴關係
在構建腳本的外部依賴關係中,說明了如何向構建腳本添加外部依賴關係。初始化腳本也可以聲明依賴關係。您可以使用initscript()
方法執行此操作,並傳入一個聲明初始化腳本類路徑的閉包。
例子2.聲明一個初始化腳本的外部依賴
init.gradle
initscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.apache.commons:commons-math:2.0'
}
}
init.gradle.kts
initscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.apache.commons:commons-math:2.0")
}
}
傳遞給該initscript()
方法的閉包將配置ScriptHandler實例。您可以通過向classpath
配置添加依賴項來聲明初始化腳本類路徑。這與您聲明Java編譯類路徑的方式相同。您可以使用聲明依賴項中描述的任何依賴項類型,項目依賴項除外。
聲明瞭初始化腳本的類路徑後,您可以像使用該類路徑上的任何其他類一樣,使用初始化腳本中的類。以下示例將添加到前面的示例中,並使用init腳本classpath中的類。
例子3.具有外部依賴關係的初始化腳本
init.gradle
import org.apache.commons.math.fraction.Fraction
initscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.apache.commons:commons-math:2.0'
}
}
println Fraction.ONE_FIFTH.multiply(2)
init.gradle.kts
import org.apache.commons.math.fraction.Fraction
initscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.apache.commons:commons-math:2.0")
}
}
println(Fraction.ONE_FIFTH.multiply(2))
應用初始化腳本時的輸出
Groovy
> gradle --init-script init.gradle -q doNothing
2 / 5
Kotlin
> gradle --init-script init.gradle.kts -q doNothing
2 / 5
1.3.5.初始化腳本插件
類似於Gradle構建腳本或Gradle設置文件,可以將插件應用於初始化腳本。
例子4.在初始化腳本中使用插件
Groovy
init.gradle
apply plugin: EnterpriseRepositoryPlugin
class EnterpriseRepositoryPlugin implements Plugin<Gradle> {
private static String ENTERPRISE_REPOSITORY_URL = "https://repo.gradle.org/gradle/repo"
void apply(Gradle gradle) {
// ONLY USE ENTERPRISE REPO FOR DEPENDENCIES
gradle.allprojects { project ->
project.repositories {
// Remove all repositories not pointing to the enterprise repository url
all { ArtifactRepository repo ->
if (!(repo instanceof MavenArtifactRepository) ||
repo.url.toString() != ENTERPRISE_REPOSITORY_URL) {
project.logger.lifecycle "Repository ${repo.url} removed. Only $ENTERPRISE_REPOSITORY_URL is allowed"
remove repo
}
}
// add the enterprise repository
maven {
name "STANDARD_ENTERPRISE_REPO"
url ENTERPRISE_REPOSITORY_URL
}
}
}
}
}
Kotlin
init.gradle.kts
apply<EnterpriseRepositoryPlugin>()
class EnterpriseRepositoryPlugin : Plugin<Gradle> {
companion object {
const val ENTERPRISE_REPOSITORY_URL = "https://repo.gradle.org/gradle/repo"
}
override fun apply(gradle: Gradle) {
// ONLY USE ENTERPRISE REPO FOR DEPENDENCIES
gradle.allprojects {
repositories {
// Remove all repositories not pointing to the enterprise repository url
all {
if (this !is MavenArtifactRepository || url.toString() != ENTERPRISE_REPOSITORY_URL) {
project.logger.lifecycle("Repository ${(this as? MavenArtifactRepository)?.url ?: name} removed. Only $ENTERPRISE_REPOSITORY_URL is allowed")
remove(this)
}
}
// add the enterprise repository
add(maven {
name = "STANDARD_ENTERPRISE_REPO"
url = uri(ENTERPRISE_REPOSITORY_URL)
})
}
}
}
}
Groovy
build.gradle
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// tag::show-repos-task[]
repositories{
mavenCentral()
}
task showRepositories {
doLast {
repositories.each {
println "repository: ${it.name} ('${it.url}')"
}
}
}
// end::show-repos-task[]
Kotlin
build.gradle.kts
// tag::show-repos-task[]
repositories{
mavenCentral()
}
tasks.register("showRepositories") {
doLast {
repositories.map { it as MavenArtifactRepository }.forEach {
println("repository: ${it.name} ('${it.url}')")
}
}
}
// end::show-repos-task[]
應用初始化腳本時的輸出
Groovy
> gradle --init-script init.gradle -q showRepositories
repository: STANDARD_ENTERPRISE_REPO ('https://repo.gradle.org/gradle/repo')
Kotlin
> gradle --init-script init.gradle.kts -q showRepositories
repository: STANDARD_ENTERPRISE_REPO ('https://repo.gradle.org/gradle/repo')
初始化腳本中的插件可確保在運行構建時僅使用指定的存儲庫。
在初始化腳本中應用插件時,Gradle實例化插件並調用插件實例的Plugin.apply(T)方法。該gradle
對象作爲參數傳遞,可用於配置構建的各個方面。當然,可以將應用的插件解析爲外部依賴項,如初始化腳本的外部依賴項中所述