Gradle最佳實(shí)踐

一、Gradle相比Maven的優(yōu)勢(shì)

  1. 配置簡(jiǎn)潔

    Maven是用pom.xml管理,引入一個(gè)jar包至少5行代碼,Gradle只需要一行。

  2. 構(gòu)建速度快

    Gradle支持daemon方式運(yùn)行,啟動(dòng)速度快,同時(shí)有基于daemon的增量構(gòu)建,充分利用JVM的運(yùn)行時(shí)優(yōu)化,和緩存數(shù)據(jù)構(gòu)建速度相比Maven快很多。

  3. 更好的靈活性、擴(kuò)展性

    Gradle 相對(duì)于 Maven 等構(gòu)建工具, 其提供了一系列的 API 讓我們有能力去修改或定制項(xiàng)目的構(gòu)建過程。

二、基本配置

  1. 設(shè)置本地倉(cāng)庫(kù)地址

    默認(rèn)本地倉(cāng)庫(kù)地址是:~/.gradle,Windows下會(huì)占用大量C盤空間。

    設(shè)置環(huán)境變量,GRADLE_USER_HOME=/your/path

  2. 復(fù)用Maven本地倉(cāng)庫(kù)

    在repositories配置mavenLocal()即可,如果是init.gradle全局配置,參考以下init.gradle文件

    Maven本地倉(cāng)庫(kù)查找路徑:

    (1)USER_HOME/.m2/settings.xml

    (2)M2_HOME/conf/settings.xml

    (3)USER_HOME/.m2/repository

  3. 國(guó)內(nèi)鏡像加速

    國(guó)內(nèi)訪問國(guó)外倉(cāng)庫(kù)地址很慢,第一種方法是在每個(gè)項(xiàng)目中設(shè)置repositories

    repositories {
        mavenLocal()
        'maven(http://maven.aliyun.com/nexus/content/groups/public/)'
        mavenCentral()
    }
    

    更推薦的方式是類似的Maven的settings.xml全局的配置,在上一步配置的GRADLE_USER_HOME路徑下,添加init.gradle文件,以下配置文件中使用了阿里云的Gradle代理,支持jcenter、google、maven倉(cāng)庫(kù)。

    gradle.projectsLoaded {
        rootProject.allprojects {
            buildscript {
                repositories {
                    def JCENTER_URL = 'https://maven.aliyun.com/repository/jcenter'
                    def GOOGLE_URL = 'https://maven.aliyun.com/repository/google'
                    def NEXUS_URL = 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
                    all { ArtifactRepository repo ->
                        if (repo instanceof MavenArtifactRepository) {
                            def url = repo.url.toString()
                            if (url.startsWith('https://jcenter.bintray.com/')) {
                                project.logger.lifecycle "Repository ${repo.url} replaced by $JCENTER_URL."
                                println("buildscript ${repo.url} replaced by $JCENTER_URL.")
                                remove repo
                            }
                            else if (url.startsWith('https://dl.google.com/dl/android/maven2/')) {
                                project.logger.lifecycle "Repository ${repo.url} replaced by $GOOGLE_URL."
                                println("buildscript ${repo.url} replaced by $GOOGLE_URL.")
                                remove repo
                            }
                            else if (url.startsWith('https://repo1.maven.org/maven2')) {
                                project.logger.lifecycle "Repository ${repo.url} replaced by $REPOSITORY_URL."
                                println("buildscript ${repo.url} replaced by $REPOSITORY_URL.")
                                remove repo
                            }
                        }
                    }
                    jcenter {
                        url JCENTER_URL
                    }
                    google {
                        url GOOGLE_URL
                    }
                    maven {
                        url NEXUS_URL
                    }
                }
            }
            repositories {
                def JCENTER_URL = 'https://maven.aliyun.com/repository/jcenter'
                def GOOGLE_URL = 'https://maven.aliyun.com/repository/google'
                def NEXUS_URL = 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
                all { ArtifactRepository repo ->
                    if (repo instanceof MavenArtifactRepository) {
                        def url = repo.url.toString()
                        if (url.startsWith('https://jcenter.bintray.com/')) {
                            project.logger.lifecycle "Repository ${repo.url} replaced by $JCENTER_URL."
                            println("buildscript ${repo.url} replaced by $JCENTER_URL.")
                            remove repo
                        }
                        else if (url.startsWith('https://dl.google.com/dl/android/maven2/')) {
                            project.logger.lifecycle "Repository ${repo.url} replaced by $GOOGLE_URL."
                            println("buildscript ${repo.url} replaced by $GOOGLE_URL.")
                            remove repo
                        }
                        else if (url.startsWith('https://repo1.maven.org/maven2')) {
                            project.logger.lifecycle "Repository ${repo.url} replaced by $REPOSITORY_URL."
                            println("buildscript ${repo.url} replaced by $REPOSITORY_URL.")
                            remove repo
                        }
                    }
                }
                jcenter {
                    url JCENTER_URL
                }
                google {
                    url GOOGLE_URL
                }
                maven {
                    url NEXUS_URL
                }
            }
        }
    }
    
    

三、最佳實(shí)踐

  1. 多模塊配置

    稍微大點(diǎn)的項(xiàng)目都會(huì)分模塊開發(fā),Gradle相比Maven的一個(gè)優(yōu)勢(shì)是用IDEA執(zhí)行一個(gè)項(xiàng)目的代碼時(shí),會(huì)自動(dòng)編譯其依賴的其他模塊。

    在項(xiàng)目一級(jí)目錄下添加settings.gradle配置文件:

    rootProject.name = 'my-roject-name'
    
    include 'module1'
    include 'module2'
    

    其中module1、module2就是子模塊的文件夾名,在子模塊里需要有一個(gè)配置子模塊的build.gradle

    模塊內(nèi)依賴,比如module2依賴module1,在module2的build.gradle配置文件里添加:

    dependencies {
        compile project(":module1")
    }
    
  2. profile支持

    profile用來加載不同環(huán)境的的配置文件,在筆者所在公司,推薦dev、test、staging、prod四套環(huán)境。

    添加gradle.properties配置文件指定默認(rèn)profile

    profile=dev
    

    啟動(dòng)profile,加載不同路徑下的配置,在build.gradle里添加配置:

    ext {
        profile = project['profile']
    }
    sourceSets {
        main {
            resources {
                srcDirs = ["src/main/resources/", "src/main/profiles/${profile}"]
            }
        }
    }
    

    命令行參數(shù)指定profile:

    gradle build -Pprofile=prod
    
  3. 初始化gradle項(xiàng)目

    安裝gradle,并在項(xiàng)目頂級(jí)目錄下執(zhí)行:

    gradle init
    

    如果當(dāng)前目錄有pom.xml,接下來會(huì)提示是否從Maven項(xiàng)目初始化Gradle項(xiàng)目,選擇yes回車執(zhí)行。

    參數(shù)文檔:https://docs.gradle.org/current/userguide/build_init_plugin.html

  4. 引入bom文件

    pom文件在Maven中是一個(gè)很有用的功能,方便多個(gè)項(xiàng)目統(tǒng)一版本號(hào),在Maven中配置方式如下:

    <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>${spring-boot.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
    </dependencyManagement>
    

    Gradle有插件支持類似操作:

    //引入插件
    plugins {
        id "io.spring.dependency-management" version "1.0.10.RELEASE"
    }
    //引入bom
    dependencyManagement {
        imports {
            mavenBom 'org.springframework.boot:spring-boot-dependencies:${spring-boot.version}'
        }
    }
    //使用bom,不需要執(zhí)行版本號(hào)
    dependencies {
        implementation "org.springframework.boot:spring-boot-starter-web"
    }
    
  5. 引入parent文件

    在maven中執(zhí)行parent是管理多個(gè)項(xiàng)目常用的方式,parent指定了項(xiàng)目的基本配置,配置方式如下:

    <parent>
      <groupId>com.lesofn.blog</groupId>
      <artifactId>test-parent</artifactId>
      <version>0.0.1</version>
    </parent>
    

    Maven中的parent有兩個(gè)作用,一個(gè)是類似bom的統(tǒng)一管理版本,即parent中的:dependencyManagement,另一個(gè)是基礎(chǔ)jar包的引用,即父pom中的:dependencies

    在Gradle可通過上面的io.spring.dependency-management插件實(shí)現(xiàn)類似的效果:

    //引入插件
    plugins {
        id "io.spring.dependency-management" version "1.0.10.RELEASE"
    }
    //引入parent,實(shí)現(xiàn)maven中dependencyManagement的功能,不用指定版本號(hào)
    dependencyManagement {
        imports {
            mavenBom 'com.lesofn.blog:test-parent:0.0.1'
        }
    }
    //再次引入parent,實(shí)現(xiàn)maven中dependencies的功能
    dependencies {
        implementation 'com.lesofn.blog:test-parent:0.0.1'
    }
    

四、總結(jié)

經(jīng)過以上配置,基本覆蓋了Gradle開發(fā)過程中的大部分問題,如果還有什么問題,歡迎留言討論。

本文作者:木小豐,美團(tuán)Java高級(jí)工程師,關(guān)注架構(gòu)、軟件工程、全棧等,不定期分享軟件研發(fā)過程中的實(shí)踐、思考。

博客地址:https://lesofn.com/archives/gradle-zui-jia-shi-jian

公共號(hào):Java研發(fā)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容