2

Gradle最佳实践

 3 years ago
source link: http://www.cnblogs.com/lesofn/p/14270731.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、Gradle相比Maven的优势

  1. 配置简洁

    Maven是用pom.xml管理,引入一个jar包至少5行代码,Gradle只需要一行。

  2. 构建速度快

    Gradle支持daemon方式运行,启动速度快,同时有基于daemon的增量构建,充分利用JVM的运行时优化,和缓存数据构建速度相比Maven快很多。

  3. 更好的灵活性、扩展性

    Gradle 相对于 Maven 等构建工具, 其提供了一系列的 API 让我们有能力去修改或定制项目的构建过程。

二、基本配置

  1. 设置本地仓库地址

    默认本地仓库地址是:~/.gradle,Windows下会占用大量C盘空间。

    设置环境变量,GRADLE_USER_HOME=/your/path

  2. 复用Maven本地仓库

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

    Maven本地仓库查找路径:

    (1)USER_HOME/.m2/settings.xml

    (2)M2_HOME/conf/settings.xml

    (3)USER_HOME/.m2/repository

  3. 国内镜像加速

    国内访问国外仓库地址很慢,第一种方法是在每个项目中设置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仓库。

    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
                }
            }
        }
    }

三、最佳实践

  1. 多模块配置

    稍微大点的项目都会分模块开发,Gradle相比Maven的一个优势是用IDEA执行一个项目的代码时,会自动编译其依赖的其他模块。

    在项目一级目录下添加settings.gradle配置文件:

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

    其中module1、module2就是子模块的文件夹名,在子模块里需要有一个配置子模块的build.gradle

    模块内依赖,比如module2依赖module1,在module2的build.gradle配置文件里添加:

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

    profile用来加载不同环境的的配置文件,在笔者所在公司,推荐dev、test、staging、prod四套环境。

    添加 gradle.properties 配置文件指定默认profile

    profile=dev

    启动profile,加载不同路径下的配置,在build.gradle里添加配置:

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

    命令行参数指定profile:

    gradle build -Pprofile=prod
  3. 初始化gradle项目

    安装gradle,并在项目顶级目录下执行:

    gradle init

    如果当前目录有pom.xml,接下来会提示是否从Maven项目初始化Gradle项目,选择yes回车执行。

    参数文档: https://docs.gradle.org/current/userguide/build_init_plugin.html

  4. 引入bom文件

    pom文件在Maven中是一个很有用的功能,方便多个项目统一版本号,在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,不需要执行版本号
    dependencies {
        implementation "org.springframework.boot:spring-boot-starter-web"
    }
  5. 引入parent文件

    在maven中执行parent是管理多个项目常用的方式,parent指定了项目的基本配置,配置方式如下:

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

    Maven中的parent有两个作用,一个是类似bom的统一管理版本,即parent中的:dependencyManagement,另一个是基础jar包的引用,即父pom中的:dependencies

    在Gradle可通过上面的io.spring.dependency-management插件实现类似的效果:

    //引入插件
    plugins {
        id "io.spring.dependency-management" version "1.0.10.RELEASE"
    }
    //引入parent,实现maven中dependencyManagement的功能,不用指定版本号
    dependencyManagement {
        imports {
            mavenBom 'com.lesofn.blog:test-parent:0.0.1'
        }
    }
    //再次引入parent,实现maven中dependencies的功能
    dependencies {
        implementation 'com.lesofn.blog:test-parent:0.0.1'
    }

四、总结

经过以上配置,基本覆盖了Gradle开发过程中的大部分问题,如果还有什么问题,欢迎留言讨论。

本文作者: 木小丰 ,美团Java高级工程师,关注架构、软件工程、全栈等,不定期分享软件研发过程中的实践、思考。

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

公共号:Java研发

%E4%BA%8C%E7%BB%B4%E7%A0%81%E5%B0%8F_1607785087313-20210112224942778.jpg


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK