maven已经满足了开发人员百分之九十九的需求,为什么还要用gradle?
因为我们是技术人。
在开始装逼之前,放一张spring官方的消息图:
上面这位Andy Wilkinson是springboot团队大佬,他在六月8号发布了一条推文,大致意思是:在Springboot2.3版本之后,我们将构建工具从maven迁移到gradle上,如果您对我们进行更改的原因和方式感兴趣,我刚刚发布了一篇博客文章,其中包含一些详细信息:why gradle逐步构建……。现在,平均而言,CI构建速度提高了3到4倍,本地构建速度提高了20到30倍…… 正如评论区中的大佬发言, 构建速度是第一要义,在这一点上,似乎Gradle完爆了maven,究竟gradle是何方神圣,在下面我们会从几个方面和通过一个简单的项目改造来聊一聊这个java世界构建工具的翘楚。
灵活性
Google选择Gradle作为Android的官方构建工具 ; 不是因为构建脚本是代码,而是因为Gradle的建模方式可以用最基本的方式扩展。Gradle的模型还允许将其用于C / C ++的本机开发,并且可以扩展为涵盖任何生态系统。例如,Gradle在使用Tooling API的时候就考虑了嵌入。
Gradle和Maven都提供了配置约定。但是,Maven提供了一个非常僵化的模型,使定制变得乏味,有时甚至是不可能的。尽管这可以使您更容易理解任何给定的Maven构建,但是只要你没有任何特殊要求,它也就不适合许多自动化问题。另一方面,Gradle的构建考虑了授权和负责任的用户。
性能
缩短构建时间是加快项目产出的最直接方法之一。Gradle和Maven都采用某种形式的并行项目构建和并行依赖项解析。最大的不同是Gradle避免工作和增加工作量的机制。使Gradle比Maven快得多的前3个功能是:
- 增量 — Gradle通过跟踪任务的输入和输出并仅运行必要的内容,并且仅在可能时处理已更改的文件,从而避免了工作。
- Build Cache(构建缓存) —重用具有相同输入的任何其他Gradle构建的构建输出,包括在机器之间。
- Gradle Daemon —一个长期存在的过程,可将构建信息“热”存储在内存中。
在Gradle与Maven的性能对比中,这些和更多的性能功能使Gradle在几乎每种情况下的速度至少是其两倍(对于使用构建缓存的大型构建而言,则要快100倍)。
注意: Gradle和Maven用户都可以利用Gradle Enterprise中可用的Build Cache技术。Gradle用户通常可将构建时间减少约50%,而Maven用户通常可将构建时间减少约90%
就减少项目的构建时间而言,Springboot将构建迁移到Gradle无疑是成功的。如上所述,在CI和开发人员自己的计算机上,基于Maven的完整构建都需要一个小时或更长时间。在过去的四个星期中,Gradle的平均成功构建时间为9分22秒,如以下屏幕截图所示:
依赖管理
两种构建系统都提供了内置功能,可以解决可配置存储库中的依赖项。两者都可以在本地缓存依赖项并并行下载它们。
作为库使用者,Maven允许重写一个依赖项,但只能按版本。Gradle提供了可自定义的依赖关系选择和替换规则,这些规则可以声明一次,并在项目范围内处理不需要的依赖关系。这种替换机制使Gradle可以一起构建多个源项目以创建复合构建。
Maven具有很少的内置依赖项作用域,这些作用域在常见的情况下(例如使用测试夹具或代码生成)强制使用笨拙的模块体系结构。例如,单元测试和集成测试之间没有分隔。Gradle允许自定义依赖项范围,它提供了更好的建模和更快的构建。
Maven依赖关系冲突解决方案的工作路径最短,这受声明顺序影响。Gradle解决了所有冲突,选择了图中最高版本的依赖项。此外,使用Gradle可以将版本声明为严格,这使它们可以优先于传递版本,从而可以降级依赖项。
作为库生产者,Gradle允许生产者声明“ api”和“ implementation”依赖项,以防止有害的库泄漏到使用者的类路径中。Maven允许发布者通过可选的依赖项提供元数据,但仅作为文档提供。Gradle完全支持功能变体和可选依赖项。
单从依赖写法上来说,Gradle的Groovy DSL较与xml的maven,更为java开发人员所喜爱,例如以下为我一个多模块分布式项目的父pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>editor-common</module>
<module>editor-api</module>
<module>editor-service</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.onesports.editor</groupId>
<artifactId>odf-editor-system</artifactId>
<version>1.0.0-SNAPSHOT</version>
<description>一体ODF模板编辑器平台</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<mybatis.plus.version>3.3.1</mybatis.plus.version>
<lombok.version>1.16.10</lombok.version>
<fast.json>1.2.72</fast.json>
<hu.tool.version>5.3.9</hu.tool.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.21</druid.version>
<knife4j.version>1.0.4.RELEASE</knife4j.version>
<beetl.version>3.1.7.RELEASE</beetl.version>
<jwt.version>3.5.0</jwt.version>
<validator.version>6.0.13.Final</validator.version>
<ftp.version>0.1.51</ftp.version>
<h2.version>1.4.200</h2.version>
</properties>
<developers>
<developer>
<name>xiejiarong</name>
<email>937890254@qq.com</email>
<url>https://gitee.com/sophis/odf-editor</url>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.gitee.sophis</groupId>
<artifactId>spring-boot-knif4j-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<!-- 轻巧工具类-->
<dependencies>
<!-- JWT鉴权工具-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!-- beetl模板-->
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>${beetl.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hu.tool.version}</version>
</dependency>
<dependency>
<groupId>com.gitee.sophis</groupId>
<artifactId>spring-boot-knif4j-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- 解析xml -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
<!-- 数据库-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fast.json}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
<version>${h2.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!--mybatis plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!-- 表单校验-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${validator.version}</version>
</dependency>
<!-- ftp-->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>${ftp.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!-- Compiler 插件, 设定 JDK 版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<!-- 打包 jar 文件时,配置 manifest 文件,加入 lib 包的 jar 依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
<executions>
<execution>
<configuration>
<archive>
<manifest>
<!-- Add directory entries -->
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
<!-- resource -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
<!-- install -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
</plugin>
<!-- clean -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
</plugin>
<!-- ant -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
<!-- dependency -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!-- Java Document Generate -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- YUI Compressor (CSS/JS压缩) -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<version>1.5.1</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>compress</goal>
</goals>
</execution>
</executions>
<configuration>
<encoding>UTF-8</encoding>
<jswarn>false</jswarn>
<nosuffix>true</nosuffix>
<linebreakpos>30000</linebreakpos>
<force>true</force>
<includes>
<include>**/*.js</include>
<include>**/*.css</include>
</includes>
<excludes>
<exclude>**/*.min.js</exclude>
<exclude>**/*.min.css</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<!-- 资源文件配置 -->
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
而在前几天我成功将其迁移到gradle时,它的写法变成这样子:
/*
* This file was generated by the Gradle 'init' task.
*/
apply from: "version.gradle"
buildscript {
ext {
springBootVersion = '2.3.1.RELEASE'
dependencyManagementPluginVersion = '1.0.10.RELEASE'
}
repositories {
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("io.spring.gradle:dependency-management-plugin:${dependencyManagementPluginVersion}")
}
}
allprojects {
group = 'com.onesports.editor'
version = '1.0.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'idea'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
[compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'
// 编译字符集
tasks.withType(JavaCompile) { options.encoding = 'utf-8' }
}
subprojects {
apply plugin: 'io.spring.dependency-management'
// apply plugin: 'org.springframework.boot'
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}")
}
}
repositories {
mavenLocal()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.16.10'
annotationProcessor 'org.projectlombok:lombok:1.16.10'
compile 'com.gitee.sophis:spring-boot-knif4j-starter:1.0.7.RELEASE'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.3.1.RELEASE'
}
}
单纯从代码量上来说,gradle会比maven的配置少很多,而且从语法上来讲,Groovy DSL更容易理解和拓展,写起来非常爽!
制品发布
喜欢开源的朋友,可能经常会利用maven发布自己的开源工具包到网上供其他人使用,在发布这一项上maven扳回一城,Maven原生支持maven jar的格式,发布很简单;而Gradle虽说既支持Maven又支持Gradle,但是就要我们自己做很多额外的工作。比如Maven要发布制品,只需要配置远程仓库的参数:
<distributionManagement>
<repository>
<id>internal</id>
<name>Internal Release Repository</name>
<url>http://repository.springsource.com/maven/bundles/release</url>
</repository>
</distributionManagement>
而gradle发布制品,还需要生成pom文件:
uploadArchives {
repositories {
mavenDeployer {
//为Pom文件做数字签名
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
repository(url: "http://repository.springsource.com/maven/bundles/release") {
authentication(userName: username, password: password)
}
//构造项目的Pom文件
pom.project {
name project.name
packaging 'jar'
description 'description'
}
}
}
}
一定要使用Gradle?
其实,Gradle较于maven,相当于mybatis-plus较于mybatis, 同样的工具,有增强的地方,但是不代表新的就是好的,maven虽然配置比较冗长,但是发展了这么多年,目前非常多的开源项目和IDE对maven的支持度绝对是高于gradle的,合适自己的才是好的,只是作为一个技术人的角度来说,why not have a try? 稳定好用绝对不是我们原地踏步、不愿迈出舒适圈的理由,作为一个程序开发人员,应该有一定的猎奇心理和探索精神,而且学习Gradle对于Android的学习也是有一定的帮助,毕竟谷歌公司官方指定的安卓构建工具。
总结
如果你打算学习一下Gradle,那么恭喜你又学会了一门构建工具的使用和脚本语言;如果你是快乐的maven使用者,那么请继续支持对你有用有效的构建工具。