zoukankan      html  css  js  c++  java
  • Gradle最佳实践

    一、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研发

  • 相关阅读:
    微信小程序之界面交互反馈
    微信小程序引入腾讯地图API方法
    微信小程序动态修改页面标题setNavigationBarTitle
    JavaScript中||和&&的运算
    微信小程序 使用include导入wxml文件注意的问题
    idea中文乱码及maven项目配置问题
    Linux常用命令大全
    2018年深圳,武汉房价走势分析
    redis安装,windows,linux版本并部署服务
    dubbo基础学习总结
  • 原文地址:https://www.cnblogs.com/lesofn/p/14270731.html
Copyright © 2011-2022 走看看