博客 / 詳情

返回

【效率提升】maven 轉 gradle 實戰 | 京東雲技術團隊

一、靈魂三問

1、gradle 是什麼?

一個打包工具, 是一個開源構建自動化工具,足夠靈活,可以構建幾乎任何類型的軟件,高性能、可擴展、能洞察等。其中洞察,可以用於分析構建過程中數據,提供分析參考,方便排查問題和不斷優化構建性能,以下一次編譯分析報告。

2、有什麼優勢

參考官方文章,針對包含10 子模塊的工程,相對 maven 構建速度,大概有 2-3 倍的性能提升,增量編譯大概 7 倍的性能提升,參考官方

實測對比:

gradle 耗時 maven 耗時
全新構建(clean 及下載依賴包) 1m 35s 1m58s
全新構建(clean) 43s 60s
增量構建 14s 43s

gradle 執行命令: time gradle clean build package -x test

mvn 執行的命令: time mvn clean package -Dmaven.test.skip=true -f $(pwd) -T 1C -Dmaven.artifact.threads=16

綜述,經過多輪測試,在增量編譯場景優勢比較突出平均有 2 倍的性能提升,工程模塊越多效率提升越大。

3、遷移是否容易

摸着心口説,並不容易,雖然官方提供了一鍵遷移的工具,但是還是有一定學習成本,但改造完成確實節省了大把的時間,尤其是改了一兩行代碼再次編譯時。

二、動動手試試

1、安裝 gradle

推薦使用 sdkman ,主要用於工具多版本管理的工具,如 java 、gradle 、maven 等可以根據實際情況安裝使用其中某個一個版本,如jdk8,jdk11 等,版本間切換非常簡便。 sdk 介紹:

sdk install  gradle 8.1.1

2、執行遷移命令

在當前 maven 工程下,執行如下的命令。

gradle init 
Found a Maven build. Generate a Gradle build from this? (default: yes) [yes, no] yes
Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] no

不出意外下,會在默認子模塊下添加 build.gradle 文件,如下圖:

文件解釋:

1)buildSrc/main/groovy/com.jd.pegasus.java-conventions.gradle :裏面配置的是內網私服庫地址。

repositories {
    mavenLocal()
    maven {
        url = uri('http://artifactory.jd.com/libs-releases')

        allowInsecureProtocol = true
    }

    maven {
        url = uri('http://artifactory.jd.com/libs-snapshots')

         allowInsecureProtocol = true
    }
    maven {
        url "https://plugins.gradle.org/m2/"
    }

}

2)gradle.properties :配置環境變量,必須設置 jvm 的參數,否則很容易 oom 。 更多配置

# gradle jvm 設置
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# 開啓並行編譯
org.gradle.parallel=true



3)build.gradle :包含了編譯過程中使用的插件,id 'com.jd.pegasus.java-conventions' 代表自定義的插件。 dependencies 為工程所使用的依賴。

plugins {
    id 'com.jd.pegasus.java-conventions'
}

dependencies {
    api project(':pegasus-service')
    api project(':pegasus-common')
    implementation 'org.springframework.boot:spring-boot:2.1.9.RELEASE'
    api project(':component-metric')
    testImplementation 'org.springframework.boot:spring-boot-starter-test:2.1.9.RELEASE'
    annotationProcessor 'org.projectlombok:lombok:1.18.10'
}

description = 'pegasus-worker'

這裏面有一個dependencies 依賴項中 api 與 implementation 區別,參見如下解釋:

假設你正在維護一個名為 MyLibrary 的庫,它依賴於另一個庫 InternalLibrary。你希望 MyLibrary 的用户能夠使用 InternalLibrary 中的某些類和方法,但不希望他們使用其他類和方法。在這種情況下,你可以在 MyLibrary 的 build.gradle 文件中使用 api 配置來聲明對 InternalLibrary 的依賴:

dependencies {

api project(':InternalLibrary')

}

這樣,當其他模塊依賴於 MyLibrary 時,它們也能夠訪問 InternalLibrary 中的類和方法。

但是,如果你不希望 MyLibrary 的用户能夠訪問 InternalLibrary 中的任何內容,你可以在 MyLibrary 的 build.gradle 文件中使用 implementation 配置來聲明對 InternalLibrary 的依賴:

dependencies {

implementation project(':InternalLibrary')

}

這樣,當其他模塊依賴於 MyLibrary 時,它們將無法訪問 InternalLibrary 中的任何內容。

簡單點就是如果你想把你依賴組件,讓使用你組件人也知道的明明白白的也能使用,那你就用 api 把組件傳遞下去 ,反之就用 implementation ,就自個偷摸使用了,對第三方隱藏了一些內部細節。

3、gitignore 排除不要的目錄和文件

# Gradle generated files
build/
.gradle/
/out/
/.gradle/

4、允許以不安全的方式訪問私服庫

# 在這個文件裏面,buildSrc/main/groovy/com.jd.pegasus.java-conventions.gradle 

repositories {
    mavenLocal()
    maven {
        url = uri('http://artifactory.jd.com/libs-releases')

        allowInsecureProtocol = true
    }
}



5、解決 lombok 引發的編譯問題

通過 lombok 註解會在編譯過程中把註解的類進行擴展,添加 get 、set 、toString 方法等。

# 在編譯出錯的模塊裏面 build.gradle 文件中添加註解處理器,annotationProcessor  如下:
dependencies {
    api project(':pegasus-service')
    annotationProcessor 'org.projectlombok:lombok:1.18.10'
}

6、解決版本依賴衝突

版本衝突指同依賴組件出現不同的版本情況,如pegasus-common 模塊依賴的 fastjson 有1.2.83-jdsec.rc1, 1.2.29 and 1.2.12 三個版本,gradle 會自動處理仲裁,規則有以下幾點:

1)衝突時會默認採用最新的版本。

2)通過 strictly 標記主要用於降級到指定的版本,如傳遞依賴引入的版本高,當前版本不兼容,那可以通過這個關鍵字設置指定的版本。

implementation('com.alibaba:fastjson'){   
  version{       
    strictly("1.2.12")    
  } 
}
或者簡寫為 
implementation 'com.alibaba:fastjson:1.2.29!!!'

3)force 的優先級會比較高,會覆蓋 strictly 策略

configurations.all {
    resolutionStrategy {
        // 在這裏定義您的依賴解析規則
        //force 'com.alibaba:fastjson:1.2.12'
    }
}

排查某個模塊的依賴衝突

gradle :pegasus-common:dependencyInsight --configuration compileClasspath --dependency com.alibaba:fastjson

7、如何構建 zip 包

以 springboot 為例,參考如下代碼即可,在子工程 build.gradle 文件裏。

。
plugins {
    id 'com.jd.pegasus.java-conventions'
    // 引入springboot 插件
    id 'org.springframework.boot' version '2.5.6'
}

// 指定 jar 啓動的入口函數
bootJar {
    manifest {
        attributes 'Main-Class': 'com.jd.pegasus.Application'
    }
}
// 構建 zip 壓縮包,包含啓動腳本 bin 目錄和 配置文件 conf 目錄
task packageZip(type: Zip) {
    archiveFileName = "${project.name}-${project.version}.zip"
    destinationDirectory = file("${project.buildDir}")

    from("${project.projectDir}/src/main/bin") {
        into "bin"
    }
    from("${project.buildDir}/resources/main/conf") {
        into "conf"
    }

    from("${project.buildDir}/libs/${project.name}-${project.version}.jar") {
        into "lib"
    }
    // 表示此任務的運行依賴其它 子任務。
    dependsOn bootJar
    dependsOn build
}

8、執行構建命令

# -x test 排除單測
gradle clean  build package -x test  

三、附錄參考

  1. 一文搞懂Gradle的依賴管理和版本決議
  2. gradle 與 maven 性能對比
  3. 爬坑指南 -- 理解 Plugin、Task、構建流程
  4. 如何定位和解決依賴衝突
  5. Gradle依賴之‘五種依賴配置’
  6. Migrating Builds From Apache Maven

後記:

聽説 maven 不甘寂寞,由 gradle 和 Takari 的靈感,做了一個守護的 mvnd ,在增量編譯場景效率槓槓的,有時間測試對比下。 mvnd 參考

作者:京東科技 寧利廣
來源:京東雲開發者社區 轉載請註明來源
user avatar yunduanderizi_5c7f6d367b5d0 頭像 youfujideshangpu 頭像 u_16213691 頭像 u_14191 頭像
4 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.