推薦 9 個 Gradle 優(yōu)秀實踐,進階必備!
1.使用 Gradle 包裝器
包裝器是項目中包含的特殊腳本,用于下載正確的 Gradle 版本并執(zhí)行構(gòu)建。
使用包裝器有 3 大優(yōu)點:
- 不需要在本地安裝 Gradle 來進行構(gòu)建
- 可以始終使用項目支持的 Gradle 版本。
- 更新Gradle版本很容易
如果你的項目中當(dāng)前沒有包裝器,在 Linux 中可以通過運行 ./gradlew <task-name> 來添加,在Windows 中使用 gradlew.bat <task-name>,那么就不會出錯。
2.停止清理項目
如果你每次構(gòu)建時都執(zhí)行清理,那么會造成極大的時間浪費,如下:
./gradlew clean build
Gradle 有一個很的強功能,稱為增量構(gòu)建,意味著如果更改項目中的某些內(nèi)容并運行構(gòu)建,它只會根據(jù)該更改運行必要的任務(wù)。例如,如果只修改測試類,Gradle 不需要重新編譯生產(chǎn)代碼。增量構(gòu)建意味著微小的更改構(gòu)建速度會非???,從而幫助開發(fā)人員完成更多工作。
3.添加settings.gradle
settings.gradle文件通常位于項目的根目錄中,用于指定項目名稱以及要添加到構(gòu)建中的子項目。
示例:
rootProject.name = 'settings-example'
include 'some-subproject'
不過,settings.gradle是可選的。
如果缺省該文件,Gradle 將會使用基于目錄名稱的項目名稱,如果項目被克隆到不同名稱的目錄,則其項目名稱將不正確。例如,這可能發(fā)生在 CI 服務(wù)器上。
還有性能影響。如果省略settings.gradle,Gradle 會遞歸地在目錄樹中向上導(dǎo)航以查找此類文件。這可能會產(chǎn)生大量不必要的文件讀取。
4. 將任務(wù)移至buildSrc
buildSrc目錄位于項目的根目錄中,可以包含 Groovy、Kotlin 或 Java 源代碼。如果build.gradle中有一些任務(wù)代碼,則可以轉(zhuǎn)移到buildSrc,原因有 3 個:
- 清理build.gradle,使其更容易理解
- 將任務(wù)實現(xiàn)與聲明分開
- 對于多項目構(gòu)建,任務(wù)可以在其他子項目中使用
例如下面這個不太友好的 build.gradle 示例:
abstract class RollercoasterTask extends DefaultTask {
@Input
abstract Property<String> getFavouriteCoaster()
RollercoasterTask() {
favouriteCoaster.convention('Space mountain')
}
@TaskAction
def tellMeMyFavourite() {
println "Your favourite coaster is ${favouriteCoaster.get()}!"
}
}
tasks.register('coaster', RollercoasterTask) {
favouriteCoaster = 'Super-duper loopy coaster'
}
隨著build.gradle 的增長,這種代碼會讓你頭暈?zāi)垦!=鉀Q辦法就是在與build.gradle相同的級別創(chuàng)建buildSrc目錄,結(jié)構(gòu)如下:
├── build.gradle
├── buildSrc
│ └── src
│ └── main
│ └── groovy
│ └── com
│ └── tomgregory
│ └── RollercoasterTask.groovy
可以將類定義從build.gradle轉(zhuǎn)移到RollercoasterTask.groovy中。只需包含相關(guān)的package和import 即可。如下:
package com.tomgregory
import org.gradle.api.DefaultTask
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
abstract class RollercoasterTask extends DefaultTask {
@Input
abstract Property<String> getFavouriteCoaster()
RollercoasterTask() {
favouriteCoaster.convention('Space mountain')
}
@TaskAction
def tellMeMyFavourite() {
println "Your favourite coaster is ${favouriteCoaster.get()}!"
}
}
在build.gradle中,可以用單個 import 語句替換類定義。
import com.tomgregory.RollercoasterTask
tasks.register('coaster', RollercoasterTask) {
favouriteCoaster = 'Super-duper loopy coaster'
}
這樣就清晰多了。
5. 并行運行測試
可以充分利用可用的 CPU 內(nèi)核來并行運行測試,build.gradle 添加如下配置:
test {
maxParallelForks 3
}
完成此操作后,Gradle 將會并行執(zhí)行測試。這里配置了3個執(zhí)行器,可根據(jù)實際配置此參數(shù)。
6. 項目進行版本化
對 Gradle 項目進行版本控制可以讓你更輕松地了解何時引入了更改。當(dāng)其他人使用你的項目時,這一點尤其重要。
例如,Gradle 本身使用相當(dāng)標(biāo)準(zhǔn)的版本號系統(tǒng),其中包括主版本、次版本和補丁版本。
這樣做的好處是 Gradle 用戶,在升級 Gradle 時可以輕松了解更改的范圍。當(dāng)主要版本增加時,這表明可能會有重大更改,我們應(yīng)該閱讀發(fā)行說明。
在 Gradle 中,設(shè)置版本號是在build.gradle中完成的,如下所示:
version = '0.1.0'
7. 將任務(wù)聲明封裝在插件中
任務(wù)聲明是創(chuàng)建某個任務(wù)類的實例時,通常配置一些任務(wù)屬性。
如下創(chuàng)建了一個名為copyQuote的 Copy 任務(wù):
project.tasks.register('copyQuote', Copy) {
from 'quote.txt'
into "$project.buildDir/quotes"
filter(ReplaceTokens, tokens: [CHARACTER: 'Tweedledee'])
}
事實上,在build.gradle中聲明此任務(wù)可能會導(dǎo)致幾個問題:
- 額外的代碼使得從高層次理解build.gradle變得更加困難
- 如果在不同的子項目中聲明類似的任務(wù),可能會出現(xiàn)重復(fù)
解決方案是將邏輯移至插件中,如果只需要在自己的項目(而不是其他項目)中使用該插件,則可以在buildSrc目錄中定義它。
.
├── build.gradle
├── buildSrc
│ └── src
│ └── main
│ ├── groovy
│ │ └── com
│ │ └── tomgregory
│ │ ├── WonderlandPlugin.groovy
將copyQuote任務(wù)移動到插件類中,代碼如下:
package com.tomgregory
import org.apache.tools.ant.filters.ReplaceTokens
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.Copy
class WonderlandPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('wonderland', WonderlandPluginExtension)
project.tasks.register('copyQuote', Copy) {
from 'quote.txt'
into "$project.buildDir/quotes"
filter(ReplaceTokens, tokens: [CHARACTER: extension.characterName.get()])
}
}
}
現(xiàn)在build.gradle可以大大簡化。
plugins {
id 'wonderland'
}
wonderland {
characterName = 'Tweedledee'
}
8. 優(yōu)化存儲庫
在build.gradle中聲明存儲庫告訴 Gradle 應(yīng)該在哪里查找構(gòu)建應(yīng)用程序所需的依賴項。
例如,在這里我們告訴 Gradle 查看我的自定義本地 Maven 存儲庫和 Maven Central。
repositories {
maven {
name = 'tomRepo'
url 'http://localhost:8081/repository/snapshots'
allowInsecureProtocol true
credentials(PasswordCredentials)
}
mavenCentral()
}
假設(shè)同一個項目需要這些依賴項來構(gòu)建 Java 應(yīng)用程序。
dependencies {
implementation group: 'com.tom', name: 'artifact-to-publish', version: '1.0-SNAPSHOT'
implementation 'commons-lang:commons-lang:2.6'
implementation 'com.google.guava:guava:30.1.1-jre'
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
implementation 'org.hibernate:hibernate-validator:7.0.1.Final'
}
第一個依賴項來自本地 Maven 存儲庫,但其他依賴項可在 Maven Central 中找到。
9. 切勿提交密碼
你是否曾經(jīng)將密碼提交到版本控制中然后遭受領(lǐng)導(dǎo)的鄙夷,或者被安全公司審查出安全問題。接下來我們將介紹如何避免。
不過,這已經(jīng)成為過去,因為 Gradle 提供了許多我們可以將憑證移出項目的方法。
示例:
repositories {
maven {
name = 'tomsRepo'
url 'https://xxx.com/maven/demo/'
credentials(PasswordCredentials)
}
}
那么 Gradle 將自動查找屬性<repositoryName>Username和<repositoryName>Password.
你可以在命令行上傳遞這些參數(shù)或在~/.gradle/gradle.properties中設(shè)置,如下:
// gradle.properties 中配置
tomsRepoUsername=myusername
tomsRepoPassword=mypassword
另一種方法是直接訪問 Gradle 屬性:
repositories {
maven {
url 'https://xxx.com/maven/demo/'
credentials {
username 'toms'
password property('mypw')
}
}
}
在命令行或~/.gradle/gradle.properties中傳遞密碼。
命令行示例:
./gradlew build --refresh-dependencies -Pmypw=<password>
在
~/.gradle/gradle.properties示例:
mypw=mypassword