动态

详情 返回 返回

【效率提升】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 pulsgarney 头像 chenjiabing666 头像 asmallwhitecat 头像 javalover 头像 jerryc 头像 yaochujiadetiebanshao 头像 yingyongwubideyumaoqiu 头像 fannaodeshafa 头像 webshijie 头像 ninedata 头像 kuaishoutech 头像 fjc0k 头像
点赞 13 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.