gradle和maven有哪些区别

gradle和maven都可以用来构建java程序,甚至在某些情况下,两者还可以互相转换,那么他们两个的共同点和不同点是什么?我们如何在项目中选择使用哪种技术呢?一起来看看吧。

gradle和maven的比较

虽然gradle和maven都可以作为java程序的构建工具。但是两者还是有很大的不同之处的。我们可以从下面几个方面来进行分析。

可扩展性

Google选择gradle作为android的构建工具不是没有理由的,其中一个非常重要的原因就是因为gradle够灵活。一方面是因为gradle使用的是groovy或者kotlin语言作为脚本的编写语言,这样极大的提高了脚本的灵活性,但是其本质上的原因是gradle的基础架构能够支持这种灵活性。

你可以使用gradle来构建native的C/C++程序,甚至扩展到任何语言的构建。

相对而言,maven的灵活性就差一些,并且自定义起来也比较麻烦,但是maven的项目比较容易看懂,并且上手简单。

所以如果你的项目没有太多自定义构建需求的话还是推荐使用maven,但是如果有自定义的构建需求,那么还是投入gradle的怀抱吧。

性能比较

虽然现在大家的机子性能都比较强劲,好像在做项目构建的时候性能的优势并不是那么的迫切,但是对于大型项目来说,一次构建可能会需要很长的时间,尤其对于自动化构建和CI的环境来说,当然希望这个构建是越快越好。

Gradle和Maven都支持并行的项目构建和依赖解析。但是gradle的三个特点让gradle可以跑的比maven快上一点:

增量构建

gradle为了提升构建的效率,提出了增量构建的概念,为了实现增量构建,gradle将每一个task都分成了三部分,分别是input输入,任务本身和output输出。下图是一个典型的java编译的task。

以上图为例,input就是目标jdk的版本,源代码等,output就是编译出来的class文件。

增量构建的原理就是监控input的变化,只有input发送变化了,才重新执行task任务,否则gradle认为可以重用之前的执行结果。

所以在编写gradle的task的时候,需要指定task的输入和输出。

并且要注意只有会对输出结果产生变化的才能被称为输入,如果你定义了对初始结果完全无关的变量作为输入,则这些变量的变化会导致gradle重新执行task,导致了不必要的性能的损耗。

还要注意不确定执行结果的任务,比如说同样的输入可能会得到不同的输出结果,那么这样的任务将不能够被配置为增量构建任务。

构建缓存

gradle可以重用同样input的输出作为缓存,大家可能会有疑问了,这个缓存和增量编译不是一个意思吗?

在同一个机子上是的,但是缓存可以跨机器共享.如果你是在一个CI服务的话,build cache将会非常有用。因为developer的build可以直接从CI服务器上面拉取构建结果,非常的方便。

Gradle守护进程

gradle会开启一个守护进程来和各个build任务进行交互,优点就是不需要每次构建都初始化需要的组件和服务。

同时因为守护进程是一个一直运行的进程,除了可以避免每次JVM启动的开销之外,还可以缓存项目结构,文件,task和其他的信息,从而提升运行速度。

我们可以运行 gradle –status 来查看正在运行的daemons进程。

从Gradle 3.0之后,daemons是默认开启的,你可以使用 org.gradle.daemon=false 来禁止daemons。

我们可以通过下面的几个图来直观的感受一下gradle和maven的性能比较:

使用gradle和maven构建 Apache Commons Lang 3的比较:

使用gradle和maven构建小项目(10个模块,每个模块50个源文件和50个测试文件)的比较:

使用gradle和maven构建大项目(500个模块,每个模块100个源文件和100个测试文件)的比较:

可以看到gradle性能的提升是非常明显的。

依赖的区别

gralde和maven都可以本地缓存依赖文件,并且都支持依赖文件的并行下载。

在maven中只可以通过版本号来覆盖一个依赖项。而gradle更加灵活,你可以自定义依赖关系和替换规则,通过这些替换规则,gradle可以构建非常复杂的项目。

从maven迁移到gradle

因为maven出现的时间比较早,所以基本上所有的java项目都支持maven,但是并不是所有的项目都支持gradle。如果你有需要把maven项目迁移到gradle的想法,那么就一起来看看吧。

根据我们之前的介绍,大家可以发现gradle和maven从本质上来说就是不同的,gradle通过task的DAG图来组织任务,而maven则是通过attach到phases的goals来执行任务。

虽然两者的构建有很大的不同,但是得益于gradle和maven相识的各种约定规则,从maven移植到gradle并不是那么难。

要想从maven移植到gradle,首先要了解下maven的build生命周期,maven的生命周期包含了clean,compile,test,package,verify,install和deploy这几个phase。

我们需要将maven的生命周期phase转换为gradle的生命周期task。这里需要使用到gradle的Base Plugin,Java Plugin和Maven Publish Plugin。

先看下怎么引入这三个plugin:

plugins {
  id 'base'
  id 'java'
  id 'maven-publish'
}

clean会被转换成为clean task,compile会被转换成为classes task,test会被转换成为test task,package会被转换成为assemble task,verify 会被转换成为check task,install会被转换成为 Maven Publish Plugin 中的publishToMavenLocal task,deploy 会被转换成为Maven Publish Plugin 中的publish task。

有了这些task之间的对应关系,我们就可以尝试进行maven到gradle的转换了。

自动转换

我们除了可以使用 gradle init 命令来创建一个gradle的架子之外,还可以使用这个命令来将maven项目转换成为gradle项目,gradle init命令会去读取pom文件,并将其转换成为gradle项目。

转换依赖

gradle和maven的依赖都包含了group ID, artifact ID 和版本号。两者本质上是一样的,只是形式不同,我们看一个转换的例子:

<dependencies>
  <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
  </dependency>
</dependencies>

上是一个maven的例子,我们看下gradle的例子怎写:

dependencies {
  implementation 'log4j:log4j:1.2.12'
}

可以看到gradle比maven写起来要简单很多。

注意这里的implementation实际上是由 Java Plugin 来实现的。

我们在maven的依赖中有时候还会用到scope选项,用来表示依赖的范围,我们看下这些范围该如何进行转换:

compile:

在gradle可以有两种配置来替换compile,我们可以使用implementation或者api。

前者在任何使用Java Plugin的gradle中都可以使用,而api只能在使用Java Library Plugin的项目中使用。

当然两者是有区别的,如果你是构建应用程序或者webapp,那么推荐使用implementation,如果你是在构建Java libraries,那么推荐使用api。

runtime:

可以替换成 runtimeOnly 。

test:

gradle中的test分为两种,一种是编译test项目的时候需要,那么可以使用testImplementation,一种是运行test项目的时候需要,那么可以使用testRuntimeOnly。

provided:

可以替换成为compileOnly。

import:

在maven中,import经常用在dependencyManagement中,通常用来从一个pom文件中导入依赖项,从而保证项目中依赖项目版本的一致性。

在gradle中,可以使用 platform() 或者 enforcedPlatform() 来导入pom文件:

dependencies {
  implementation platform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE') 

  implementation 'com.google.code.gson:gson'
  implementation 'dom4j:dom4j'
}

比如上面的例子中,我们导入了spring-boot-dependencies。因为这个pom中已经定义了依赖项的版本号,所以我们在后面引入gson的时候就不需要指定版本号了。

platform和enforcedPlatform的区别在于,enforcedPlatform会将导入的pom版本号覆盖其他导入的版本号:

dependencies {
  // import a BOM. The versions used in this file will override any other version found in the graph
  implementation enforcedPlatform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE')

  // define dependencies without versions
  implementation 'com.google.code.gson:gson'
  implementation 'dom4j:dom4j'

  // this version will be overridden by the one found in the BOM
  implementation 'org.codehaus.groovy:groovy:1.8.6'
}

转换repositories仓库

gradle可以兼容使用maven或者lvy的repository。gradle没有默认的仓库地址,所以你必须手动指定一个。

你可以在gradle使用maven的仓库:

repositories {
  mavenCentral()
}

我们还可以直接指定maven仓库的地址:

repositories {
  maven {
    url "http://repo.mycompany.com/maven2"
  }
}

如果你想使用maven本地的仓库,则可以这样使用:

repositories {
  mavenLocal()
}

但是mavenLocal是不推荐使用的,为什么呢?

mavenLocal只是maven在本地的一个cache,它包含的内容并不完整。比如说一个本地的maven repository module可能只包含了jar包文件,并没有包含source或者javadoc文件。那么我们将不能够在gradle中查看这个module的源代码,因为gradle会首先在maven本地的路径中查找这个module。

并且本地的repository是不可信任的,因为里面的内容可以轻易被修改,并没有任何的验证机制。

控制依赖的版本

如果同一个项目中对同一个模块有不同版本的两个依赖的话,默认情况下Gradle会在解析完DAG之后,选择版本最高的那个依赖包。

但是这样做并不一定就是正确的, 所以我们需要自定义依赖版本的功能。

首先就是上面我们提到的使用platform()和enforcedPlatform() 来导入BOM(packaging类型是POM的)文件。

如果我们项目中依赖了某个module,而这个module又依赖了另外的module,我们叫做传递依赖。在这种情况下,如果我们希望控制传递依赖的版本,比如说将传递依赖的版本升级为一个新的版本,那么可以使用dependency constraints:

dependencies {
  implementation 'org.apache.httpcomponents:httpclient'
  constraints {
    implementation('org.apache.httpcomponents:httpclient:4.5.3') {
      because 'previous versions have a bug impacting this application'
    }
    implementation('commons-codec:commons-codec:1.11') {
      because 'version 1.9 pulled from httpclient has bugs affecting this application'
    }
  }
}

注意,dependency constraints只对传递依赖有效,如果上面的例子中commons-codec并不是传递依赖,那么将不会有任何影响。

同时 Dependency constraints需要Gradle Module Metadata的支持,也就是说只有你的module是发布在gradle中才支持这个特性,如果是发布在maven或者ivy中是不支持的。

上面讲的是传递依赖的版本升级。同样是传递依赖,如果本项目也需要使用到这个传递依赖的module,但是需要使用到更低的版本(因为默认gradle会使用最新的版本),就需要用到版本降级了。

dependencies {
  implementation 'org.apache.httpcomponents:httpclient:4.5.4'
  implementation('commons-codec:commons-codec') {
    version {
      strictly '1.9'
    }
  }
}

我们可以在implementation中指定特定的version即可。

strictly表示的是强制匹配特定的版本号,除了strictly之外,还有require,表示需要的版本号大于等于给定的版本号。prefer,如果没有指定其他的版本号,那么就使用prefer这个。reject,拒绝使用这个版本。

除此之外,你还可以使用Java Platform Plugin来指定特定的platform,从而限制版本号。

最后看一下如何exclude一个依赖:

dependencies {
  implementation('commons-beanutils:commons-beanutils:1.9.4') {
    exclude group: 'commons-collections', module: 'commons-collections'
  }
}

多模块项目

maven中可以创建多模块项目:

<modules>
  <module>simple-weather</module>
  <module>simple-webapp</module>
</modules>

我们可以在gradle中做同样的事情settings.gradle:

rootProject.name = 'simple-multi-module' 

include 'simple-weather', 'simple-webapp'

profile和属性

maven中可以使用profile来区别不同的环境,在gradle中,我们可以定义好不同的profile文件,然后通过脚本来加载他们:

build.gradle:

if (!hasProperty('buildProfile')) ext.buildProfile = 'default' 

apply from: "profile-${buildProfile}.gradle" 

task greeting {
  doLast {
    println message
  }
}

profile-default.gradle:

ext.message = 'foobar'

profile-test.gradle:

ext.message = 'testing 1 2 3'

我们可以这样来运行:

> gradle greeting
foobar

> gradle -PbuildProfile=test greeting
testing 1 2 3

资源处理

在maven中有一个process-resources阶段,可以执行resources:resources用来进行resource文件的拷贝操作。

在Gradle中的Java plugin的processResources task也可以做相同的事情。

比如我可以执行copy任务:

task copyReport(type: Copy) {
  from file("buildDir/reports/my-report.pdf")
  into file("buildDir/toArchive")
}

更加复杂的拷贝:

task copyPdfReportsForArchiving(type: Copy) {
  from "buildDir/reports"
  include "*.pdf"
  into "buildDir/toArchive"
}

当然拷贝还有更加复杂的应用。这里就不详细讲解了。

以上就是gradle和maven有哪些区别的详细内容,更多关于gradle和maven 区别的资料请关注我们其它相关文章!

(0)

相关推荐

  • Gradle使用Maven仓库的方法

    本文介绍了Gradle使用Maven仓库的方法,分享给大家,具体如下: 在build.gradle文件中, 修改repositories如下: repositories { mavenLocal() mavenCentral() } 这样的话, 就会优先从maven的仓库中查找所需的jar包 我的maven配置本地仓库为D:\repository中(见底部的"如何修改maven本地仓库地址"), 为防止下载到C盘默认的目录下, 建议将setting.xml复制一份到C:\Users\用

  • 详解阿里云maven镜像库配置(gradle,maven)

    经常使用maven远程仓库里jar包的同学,最头疼的事情莫过于加了jar包依赖配置之后,需要漫长的下jar包的过程,因为maven仓库网站是国外网站,速度非常的慢.在国内下好jar包放到本地再加载又过于麻烦. 以前有个oschina的国内maven镜像仓库地址,现在应该是弃用了(害得我也等了半天)现在国内的话主要使用阿里云的maven镜像仓库,速度很快~~~ gradle配置:将原来的mavenCentral()直接替换掉或者放到这个的前面(默认是从上往下寻找,所以要放到mavenCentral

  • IDEA配置java开发环境(maven、gradle、tomcat)

    idea安装好以后,是需要简单的配置一下的,而且要分不同的开发环境,此处就不多扩展了,我们就一起来配置java的开发环境 准备: 1.jdk环境配置 ------- java环境变量请参考(linux环境下java开发环境配置 或 windows环境下java开发环境配置) 2.maven build工具(maven项目使用),下载地址,本地下载地址 3.gradle build工具(gradle项目使用),下载地址,本地下载地址 4.tomcat 8.x ,下载地址,本地下载地址 内容: 一.

  • 常用Maven库,镜像库及maven/gradle配置(小结)

    平时用到的库 仓库名 地址 备注 mavenCentral https://repo1.maven.org/maven2/ https://repo.maven.apache.org/maven2/ 全区最大的maven库,第二个为apache的镜像库, gradle默认地址 jcenter https://jcenter.bintray.com/anverus/tools/ bintray私有库 兼容mavenCentral中心仓库,且性能更优 google https://dl.google

  • Gradle相对于Maven有哪些优点

    一.Gradle介绍 Gradle和Maven作为自动构建工具,在项目的构建中有着广泛的应用.他们之间有各自的优缺点,这里我们讨论下他们在项目构建中的一些区别并进行比较. 首先简单介绍下Gradle和Maven.Maven主要服务于基于java平台的项目构建.依赖管理和项目信息管理.无论是小型的开源类库项目,还是大型的企业级应用:无论是传统的瀑布式开发还是流行的敏捷模式,Maven都能大显身手.Gradle是以groovy语言为基础,面向java应用为主,基于DSL语法的自动化构建工具. 虽然两

  • Android Studio新建工程默认在build.gradle中加入maven阿里源的问题

    背景: 在安卓开发时,我们时常会因为gradle时间漫长感到烦恼.通常情况下我们会在build.gradle(Project:MyApplication)中的repositories里添加阿里源,如下图所示. 而每次新建工程依然是google()和jcenter(),而且新建后自动帮你Sync,如果网速不佳则是等了好久才编译好一个新的工程. 解决方案: Android Studio新建工程自动加入maven阿里源 版本:笔者用的是AndroidStudio 3.4,其他版本略同 找到Androi

  • gradle和maven有哪些区别

    gradle和maven都可以用来构建java程序,甚至在某些情况下,两者还可以互相转换,那么他们两个的共同点和不同点是什么?我们如何在项目中选择使用哪种技术呢?一起来看看吧. gradle和maven的比较 虽然gradle和maven都可以作为java程序的构建工具.但是两者还是有很大的不同之处的.我们可以从下面几个方面来进行分析. 可扩展性 Google选择gradle作为android的构建工具不是没有理由的,其中一个非常重要的原因就是因为gradle够灵活.一方面是因为gradle使用

  • Java中的Gradle与Groovy的区别及存在的关系

    目录 一.Gradle构建的利与弊 二.Groovy的优点 三.依存关系 四.认识build.gradle 五.Gradlebuildscript 六.什么是闭包 七.Gradle只是闭包 八.探索Gradle依赖项配置 九.打包Gradle版本 十.任务 前言: 在Java项目中,有两个主要的构建系统:Gradle和Maven.构建系统主要管理潜在的复杂依赖关系并正确编译项目.还可以将已编译的项目以及所有资源和源文件打包到.war或.jar文件中.对于简单的构建,Maven和Gradle之间的

  • Java Maven构建工具中mvnd和Gradle谁更快

    目录 1.mvnd 简介 2.Gradle 简介 2.1 Gradle 优点简述 3.Gradle 使用 3.1 更换 Gradle 为国内源 3.2 项目依赖文件对比 3.3 settings.gradle VS build.gradle 3.4 打包项目 4.mvnd 5.性能对比 5.1 Maven 打包性能 5.2 mvnd 打包性能 5.3 Gradle 打包性能 6.扩展:Gradle 打包文件存放目录 总结 前言; Maven 作为经典的项目构建工具相信很多人已经用很久了,但如果体

  • 详解如何使用Android Studio开发Gradle插件

    缘由 首先说明一下为什么会有这篇文章.前段时间,插件化以及热修复的技术很热,Nuwa热修复的工具NuwaGradle,携程动态加载技术DynamicAPK,还有希望做最轻巧的插件化框架的Small.这三个App有一个共同的地方就是大量的使用了Gradle这个强大的构建工具,除了携程的框架外,另外两个都发布了独立的Gradle插件提供自动化构建插件,或者生成热修复的补丁.所以学习一下Gradle插件的编写还是一件十分有意义的事. 插件类型 Gradle的插件一般有这么几种: 一种是直接在项目中的g

  • 利用Gradle如何构建scala多模块工程的步骤详解

    前言 Scala是一门强大的语言,受到很多人的喜爱,我也曾经尝试学习过.不过Scala官网专用的构建工具SBT就不那么好用了.我曾经想将SBT的软件包保存路径设置到D盘,还想设置网络代理,不过最后都没搞明白怎么回事.相信也有很多同学想学习Scala,但是却被SBT挡在了门外.偶然之下我发现现在Gradle增加了scala插件,可以完美支持Scala项目. 前段时间终于无法忍受sbt慢如龟速的编译打包速度了.稍稍调研了一下,就果断切换到了gradle.由于调研得比较匆忙,在使用过程中遇到了各种问题

  • Gradle快速安装及入门

    1.什么是Gradle Gradle是一种结合了Ant和Maven两者优势的下一代构建工具,既有Ant构建灵活性的优点,也保留Maven约定优于配置的思想,在灵活构建和约定构建之间达到了很好的平衡. 2.安装Gradle (1)Gradle属于解压配置即可使用的软件 下载解压gradle-4.1-all.zip,例如解压到:D:/ gradle-4.1 (2)window中设置gradle环境变量: GRADLE_HOME    D:/ gradle-4.1 path              

  • 如何在Maven项目中运行JUnit5测试用例实现

    本文演示了如何如何编写JUnit 5测试用例,在Maven项目中运行JUnit 5测试用例. 编写JUnit 5测试用例 如果你是Java开发者,那么对于JUnit应该就不陌生.JUnit是Java单元测试的基础工具. JUnit目前最新的版本是JUnit 5.x,但广大的Java开发者估计还停留在JUnit 4.x,因此有必要演示下如何编写JUnit 5测试用例. 引入JUnit 5依赖 相比较JUnit 4而言,JUnit 5一个比较大的改变是JUnit 5拥有与JUnit 4不同的全新的A

随机推荐