gradle 指定springcloud 版本_Maven 程序员难道就不能快速上手 Gradle了吗?

背景

庖丁同学在混迹在古典互联网界多年,构建 Java 应用程序一直都是使用Apache Maven,mvn的那几个常用命令早已烂熟于心,在加上现代 IDE 越来越智能,应用程序的构建从来就不是事儿,但是惊喜总会出现,有一天,庖丁的工作性质发生了改变,眼前的构建工具清一色的都是 Gradle,庖丁一脸的懵逼,束手无策,难道Maven 程序员就不能快速上手 Gradle了吗?

实战性或者战术性程序员这时候做的第一件是事情,肯定是先打开 Gradle 的官方网站,快速学习一遍入门教程,先用起来,再去慢慢理解它的运行机制和设计思想,但是庖丁是解牛的,必须“依乎天理”。深刻理解事物的本质,方能游刃有余。

首先回归问题的本质,无论是 Apache Maven 还是 Gradle ,最核心的功能都是应用程序工程的构建工具,只是实现理念和使用方式上有差异。下面庖丁首先回顾下 Apache Maven 的使用方式和工作机制。

Apache Maven 的工作机制

9bb89bfed240068fbcf7fa6c8d20c7e2.png

Maven图标,来源于官网

Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.

上面这段话来自于 Apache Maven 的官网,Apache Maven是一个软件项目管理和理解工具。 基于项目对象模型(POM)的概念,Maven可以通过集中的信息来管理项目的构建,报告和文档。POM 是最基础也是最核心的组件,这也是 Maven 的配置文件命名为 pom.xml的主要原因。POM是通过 XML 文件的格式进行定义。pom.xml 文档的示例片段如下:

    4.0.0   com.mycompany.app   my-app   jar   1.0-SNAPSHOT   Maven Quick Start Archetype   http://maven.apache.org               junit       junit       4.11       test         

使用 Maven 管理项目构建时,通常第一步去官网下载Apache Maven 的安装包,配置好环境变量,就可以执行 mvn 命令了,大多数公司会通过 nexus搭建私服,对项目的依赖进行规划化管理。

我们在使用 Maven 管理项目的构建时,IDE 工具或者脚手架工具都会帮我们生成 pom.xml 文件和基本的项目骨架,然后根据项目的需要进行依赖管理,各种各样的插件是必不可少的。一切准备就绪后,我们就可以对项目进行构建了,例如编译,测试,部署等工作。所以Apache Maven 主要帮我们做了两件大事,一个是依赖版本管理,另一个就是各种构建过程。先看看Apache Maven 的构建过程。

Maven的构建过程

下面是Maven读取POM文件执行构建过程的示意图

c2b038d60646581cd5f3583a441a2efd.png

Maven 构建过程

Maven 的构建过程

总体来说,Maven项目的构建分为五个主要步骤,

  1. 读取 POM.xml 文件
  2. 选择需要构建的 profile,这个主要方便多构建目标操作,例如单元测试和集成测试,依赖项不一样
  3. 下载依赖项目,一般是 Jar 包文件,首先回去读本地仓库,然后选择读取内部私服,最后是远程公共仓库
  4. 根据构建任务的生命周期,执行构建过程和目标
  5. 执行插件,部分插件会融合在构建阶段中,一起执行。

例如对于编译这个构建任务,执行如下命令:

 mvn compile

实际上,执行是编译 compile 这个构建阶段,真正执行的是如下阶段

  1. validate
  2. generate-sources
  3. process-sources
  4. generate-resources
  5. process-resources
  6. compile

maven 对构建过程的抽象

项目的研发有生命周期,项目的构建过程也一样,是多个独立的任务,Maven 对构建构建过程的抽象中,任务是个虚拟的概念, 因为Maven基于构建生命周期的中心概念。这意味着已明确定义了构建和分发特定工件(项目)的过程。对于构建项目的人来说,这意味着仅需学习少量命令即可构建任何Maven项目,并且POM将确保它们获得所需的结果。这是一种开箱即用的设计,也是一种最佳实践。

POM 文件

执行Maven命令时,Maven根据POM文件中的配置来执行命令。

依赖项和存储库

Pom文件包含了依赖项的配置,依赖项是项目使用的外部JAR文件(Java库)。如果本地库中没有找到依赖项,Maven将从中央库下载依赖项,并存放在本地库中。本地存储库只是本机上的一个目录,这个目录位置可配置。另外除了中央库,还可以配置其他远程库,例如公司内部可以架设一个远程库供所有开发人员使用。这里我们看看 Spring Boot 的依赖项,通过三个维度对依赖包进行管理。

       org.springframework.boot     spring-boot-starter-web     2.2.6.RELEASE 
构建生命周期、阶段和目标

项目的构建通常包含数个相互独立的任务,可以独立执行,如生成文档,构建jar包等。单个任务的执行过程被称为一个构建生命周期,构建生命周期由一系列的构建阶段组成,这些构建生命周期中的每一个都由不同的构建阶段列表定义,其中,构建阶段代表生命周期中的一个阶段。每个阶段包含一系列的构建目标。

可以执行构建阶段或构建目标。阶段按顺序执行,执行一个阶段则会先执行该阶段之前的所有阶段。当执行构建阶段时,将会按顺序执行其中包含的所有构建目标。构建目标可以被分配到一个或多个构建阶段。还可以直接执行构建目标。

Maven有三个内置的构建生命周期:默认(default),清除(clean)和站点(site)。默认生命周期处理项目部署,清理(clean)生命周期处理项目清理,而站点(site)生命周期处理项目的站点文档的创建。

例如,默认生命周期包含以下阶段:

  • 验证(validate)-验证项目是否正确并且所有必要信息均可用
  • 编译(compile)-编译项目的源代码
  • 测试(test)-使用合适的单元测试框架测试已编译的源代码。这些测试不应要求将代码打包或部署
  • 打包(package)-打包已编译的代码,并将其打包为可分发的格式,例如JAR。
  • 集成测试(integration-test):处理程序包并将其部署到可以运行集成测试的环境中
  • 验证(verify):运行任何检查以验证包装是否有效并符合质量标准
  • 安装(install):将软件包安装到本地存储库中,以作为本地其他项目中的依赖项
  • 部署(deploy):在集成或发布环境中完成,将最终程序包复制到远程存储库,以便与其他开发人员和项目共享。
插件Plugin

插件是构建目标的集合,也称为MOJO (Maven Old Java Object)。可以把插件理解为一个类,而构建目标是类中的方法。构建阶段包含一系列的构建目标,可以理解为按顺序调用各个插件中的构建目标(方法),然后一系列的构建阶段组成一个构建生命周期。

Maven实际上是一个插件执行框架。如有必要,可以用java开发自定义插件。例如我们经常使用的Running MyBatis Generator With Maven

构建Profile

如果需要构建项目的不同版本,可以使用构建profile。例如,项目中需要构建开发版本、测试版本以及正式版本,这些版本可以通过在pom文件中添加不同构建profile构建。执行maven时指定不同的构建profile就可以。

小结

Apache Maven是一个软件项目管理和理解工具。 基于项目对象模型(POM)的概念,通过 XML 进行配置,构建过程基于任务的的生命周期概念。完成了依赖版本管理和项目构建过程。

对 Gradle 工具的猜想

既然 Maven 已经使用了挺好了,为什么会出现新的构建工具之一 Gradle 呢?显然 Maven 有不足之处或者痛点,想想我们日常工作中的痛点。

  • pom.xml文件非常冗长,例如 Apache Flink 的 pom(https://github.com/apache/flink/blob/master/pom.xml) 文件大概有两千行,这和 XML 的表达方式有关。
  • 构建过程非常慢,特别是大型项目。
  • 扩展性限制较大,无法和你的编程语言或者脚本打通

如果需要一个新的构建工具,你期望它最好具有哪些特征呢?

  • 兼容 Maven 的依赖管理机制,毕竟你已经有一些项目通过 Maven 管理,当然还有一些非常优秀的第三方 Jar 包,这些对你的项目运行至关重要
  • 编译和构建速度快
  • 构建文件的配置简单明了,减少冗余,特别是那些约定俗称的概念
  • 扩张性好,最好能和你使用的 Java 语言打通

万变不离其宗,构建工具的本质工作为依赖管理和项目构建,那么 Gradle 会不会给你惊喜呢?

Gradle 初见

惊讶地发现,熟悉的 pom.xml 文件不见了,取而代之的是 build.gradle文件,打开它发现 XML 格式的内容也不见了,莫慌,肯定是某种编程语言,先瞄一眼,build.gradle 脚本示例。

 plugins {     id 'java-library' } ​ repositories {     mavenCentral()     jcenter()  } dependencies {     api 'org.apache.commons:commons-math3:3.6.1'      implementation 'com.google.guava:guava:28.0-jre'      testImplementation 'junit:junit:4.13'  }

挺简洁,junit 的依赖一行就阐述清楚了

 testCompile group: 'junit', name: 'junit', version: '4.13'

如果使用 Maven 的依赖,配置片段应该是如下这样,6 行配置代码,解决了配置文件冗长的 繁琐,并且提高了可读性。

      junit     junit     4.13     test 

mavenCentral(),具备Jar 包存储仓库管理和配置,兼容 Maven 仓库,简洁的依赖管理和可配置的插件。已经具备了 Maven的基础功能。Gradle能不能解决 Maven 构建工具的痛点呢?它和Maven 对于项目构建过程的抽象和封装会一致吗?

Gradle 的工作机制

Gradle 简介

Gradle是一个开放源代码的构建自动化工具,旨在灵活地构建几乎任何类型的软件。下图是 Gradle 官网的截图,可以看出 Gradle 的雄心,加快研发人员的生产力

b38b1a843cff3f5e3b626f1935908c4f.png

图片来源于 Gradle 官网

Gradle是专注于灵活性和性能的开源构建自动化工具。 Gradle构建脚本是使用[Groovy](https://groovy-lang.org/)或[Kotlin](https://kotlinlang.org/)DSL编写的,主要有如下特质:

  • 高度可定制-Gradle以最基本的方式可定制和可扩展的方式建模。
  • 快速-Gradle通过重新使用先前执行的输出,仅处理已更改的输入并并行执行任务来快速完成任务。**
  • 功能强大–Gradle是Android的官方构建工具,并支持许多流行的语言和技术。
7ed952daae3c1ce83248fe6ddb2d5113.png

Gradle 重要核心功能

高性能

Gradle通过仅运行需要执行的任务来避免不必要的工作,因为它们的输入或输出已更改。您还可以使用构建缓存来重用以前运行的任务输出,甚至可以使用其他计算机(具有共享的构建缓存)重用任务输出。

Gradle还实施了许多其他优化措施,并且开发团队不断努力以提高Gradle的性能。

JVM基础

Gradle在JVM上运行,并且必须安装Java开发工具包(JDK)才能使用它。对于熟悉Java平台的用户来说,这是一个好处,因为您可以在构建逻辑中使用标准Java API,例如自定义任务类型和插件。它还使在不同平台上运行Gradle变得容易。

请注意,Gradle不仅限于构建JVM项目,它甚至附带对构建本机项目的支持。

约定(Conventions)

Gradle从Maven的书中抽出了一片叶子,并通过实现约定使常见类型的项目(例如Java项目)易于构建。应用适当的插件,您可以轻松地为许多项目使用苗条的构建脚本。但是这些约定并没有限制您:Gradle允许您覆盖它们,添加自己的任务以及对基于约定的版本进行许多其他自定义。

可扩展性

您可以轻松扩展Gradle以提供您自己的任务类型甚至构建模型。有关此示例,请参见Android构建支持:它添加了许多新的构建概念,例如口味和构建类型。

IDE支持

几个主要的IDE允许您导入Gradle构建并与其进行交互:Android Studio,IntelliJ IDEA,Eclipse和NetBeans。 Gradle还支持生成将项目加载到Visual Studio所需的解决方案文件。

洞察力

构建扫描提供了有关构建运行的广泛信息,可用于识别构建问题。他们特别擅长帮助您发现构建性能方面的问题。您还可以与其他人共享构建扫描,如果您需要咨询以解决构建问题,这特别有用。

主要差异和对比

Gradle和Maven之间的主要区别是灵活性,性能,用户体验和依赖性管理。 Maven与Gradle功能比较中提供了这些方面的直观概述。Gradle 官网中,对 Gradle 和 Maven 从以下几个方面做了比较详细的对比:

灵活性

Google选择Gradle作为Android的官方构建工具; 不是因为构建脚本是代码,而是因为Gradle以最基本的方式可扩展的方式进行建模。 Gradle的模型还允许将其用于C / C ++的本机开发,并且可以扩展为涵盖任何生态系统。 例如,Gradle在设计时会考虑使用其Tooling API进行嵌入。

Gradle和Maven都提供了配置约定。 但是,Maven提供了一个非常僵化的模型,使定制变得乏味,有时甚至是不可能的。 尽管这可以使您更容易理解任何给定的Maven构建,但是只要您没有任何特殊要求,它也就不适合许多自动化问题。 另一方面,Gradle的构建考虑了授权和负责任的用户。

性能

缩短构建时间是提高交付速度的最直接方法之一。 Gradle和Maven都采用某种形式的并行项目构建和并行依赖项解析。 最大的差异是Gradle避免重复工作和增加工作量的机制。 使Gradle比Maven快得多的前3个功能是:

  1. 增量性-Gradle通过跟踪任务的输入和输出并仅运行必要的内容,并且仅在可能时处理已更改的文件,从而避免了工作。
  2. Build Cache(构建缓存)—重用具有相同输入的任何其他Gradle构建的构建输出,包括在机器之间
  3. Gradle Daemon —一个长期存在的过程,可将构建信息“热”存储在内存中。

在Gradle与Maven的性能对比中,这些和更多的性能特性使Gradle在几乎每种情况下的速度至少是其两倍(对于使用构建缓存的大型构建而言,则要快100倍)。下图来自 Gradle 官网 。

898c6138142c7107c6ac3b4f595166ed.png

用户体验

Maven的任期较长,这意味着它对许多用户来说都更支持IDE。 但是,Gradle的IDE支持继续迅速提高。 例如,Gradle现在具有基于Kotlin的DSL,可提供更好的IDE体验。 Gradle团队正在与IDE开发商合作,以使编辑支持变得更好-随时关注更新。

4a3fd52023849c93b3fd4860dc2614b5.png

尽管IDE很重要,但是许多用户还是喜欢通过命令行界面执行构建操作。 Gradle提供了一个现代的CLI,该CLI具有可发现性功能,例如“ gradle task”(渐变任务),以及改进的日志记录和命令行完成功能。

最后,Gradle提供了一个基于Web的交互式UI,用于调试和优化构建:构建扫描。 这些也可以在内部托管,以允许组织收集构建历史记录并进行趋势分析,比较构建以进行调试或优化构建时间。

dbb57b393b8a01d88be10e84494450fe.png

依赖管理

两种构建系统都提供了内置功能,可以解决来自可配置存储库的依赖关系。两者都可以在本地缓存依赖项并并行下载它们。

作为库的使用者,Maven允许重写一个依赖项,但只能按版本。 Gradle提供了可自定义的依赖关系选择和替换规则,这些规则可以声明一次,并在项目范围内处理不需要的依赖关系。这种替换机制使Gradle可以一起构建多个源项目以创建复合构建。

Maven具有很少的内置依赖项作用域,这些作用域在常见的情况下(例如使用测试夹具或代码生成)迫使笨拙的模块体系结构。例如,单元测试和集成测试之间没有分隔。 Gradle允许自定义依赖项范围,从而提供了更好的建模和更快的构建。

Maven依赖关系冲突解决方案使用最短路径,这受声明顺序影响。 Gradle可以完全解决冲突,选择图中最高版本的依赖项。此外,使用Gradle可以将版本严格声明为允许其优先于传递版本的版本,从而可以降级依赖项。

作为库生产者,Gradle允许生产者声明“ api”和“实现”依赖项,以防止有害的库泄漏到使用者的类路径中。 Maven允许发布者通过可选的依赖项提供元数据,但仅作为文档提供。 Gradle完全支持功能变体和可选的依赖项。

bc403457e3719f7710d9e4092bb9aa6a.png

以上从四个方面对 Gradle 和 Maven 进行了对比,差距确实明显,但阐述都比较表象,没有深刻阐述本质的区别。Gradle和Maven对如何构建项目有根本不同的视角。 Gradle提供了一个灵活且可扩展的构建模型,该模型将实际工作委托给任务依赖关系图。 Maven使用固定,线性阶段的模型,您可以在其中附加目标(完成工作的事物)。 这可能使两者之间的迁移看起来令人生畏,但是迁移可能出奇的容易,因为Gradle遵循许多与Maven相同的约定(例如标准项目结构),并且其依赖项管理以类似的方式工作。

所以任务依赖关系图和线性阶段模型才是本质上的差别,也是研发和使用人员认知上的本质差别。

Maven 到 Gradle,认知的转变

Gradle是一种灵活而强大的构建工具,当Maven 程序员初次启动时,很容易感到恐惧。但是,了解以下核心原则将使Gradle更加容易上手,并且您将在不知道该工具的情况下熟练掌握该工具。

Gradle是通用的构建工具

Gradle允许您构建任何软件,因为它对您要构建的内容或应如何完成的工作几乎没有任何假设。最明显的限制是,依赖项管理当前仅支持与Maven和Ivy兼容的存储库以及文件系统。

这并不意味着您需要做很多工作来创建构建。 Gradle通过添加一层约定和通过插件的预构建功能,可以轻松构建通用类型的项目(例如Java库)。您甚至可以创建和发布自定义插件来封装自己的约定并构建功能。

核心模型基于任务

Gradle将其构建模型建模为任务(工作单元)的有向无环图(DAG)。这意味着构建实质上配置了一组任务,并根据它们的依赖关系将它们连接在一起以创建该DAG。创建任务图后,Gradle将确定需要按顺序运行的任务,然后继续执行它们。

此图显示了两个示例任务图,一个是抽象图,另一个是具体图,其中任务之间的依赖性表示为箭头:

0a14ce5484fd5a0c599f04b357a0ab0d.png

这样,几乎所有构建过程都可以建模为任务图,这就是Gradle如此灵活的原因之一。任务图可以由插件和您自己的构建脚本定义,任务通过任务依赖机制链接在一起。

任务本身包括:

  • 动作-做某事的工作,例如复制文件或编译源代码
  • 输入-操作使用或对其进行操作的值,文件和目录
  • 输出-操作修改或生成的文件和目录

实际上,以上所有操作都是可选的,具体取决于任务需要执行的操作。某些任务(例如标准生命周期任务)甚至没有任何动作。他们只是为了方便而将多个任务聚合在一起。

您选择要运行的任务。通过指定执行所需任务的任务来节省时间,但仅此而已。如果您只想运行单元测试,请选择执行该任务的任务-通常是测试。如果要打包应用程序,则大多数构建都为此执行组装任务。最后一件事:Gradle的增量构建支持是可靠且可靠的,因此,除非您确实想执行清理,否则避免清理任务可保持构建快速运行。

Gradle有几个固定的构建阶段

重要的是要了解Gradle分三个阶段评估和执行构建脚本:

  1. 初始化:设置构建环境,并确定哪些项目将参与其中。
  2. 配置:构造和配置用于构建的任务图,然后根据用户要运行的任务确定需要运行的任务和运行顺序。
  3. 执行: 运行在配置阶段结束时选择的任务。

这些阶段构成了Gradle的构建生命周期。

与Apache Maven术语的比较Gradle的构建阶段与Maven的阶段不同。 Maven使用其阶段将构建执行分为多个阶段。它们的作用类似于Gradle的任务图,但灵活性较差。

Maven的构建生命周期概念与Gradle的生命周期任务大致相似。

设计良好的构建脚本主要由声明性配置而不是命令式逻辑组成。可以理解,在配置阶段评估该配置。即便如此,许多此类构建也具有任务操作(例如,通过doLast {}和doFirst {}块),这些任务在执行阶段进行评估。这很重要,因为在配置阶段评估的代码不会看到在执行阶段发生的更改。

配置阶段的另一个重要方面是,每次运行构建时都要评估其中涉及的所有内容。因此,最佳做法是在配置阶段避免昂贵的工作。构建扫描可以帮助您识别此类热点。

Gradle的扩展方式不止一种

如果您仅可以使用Gradle捆绑的构建逻辑来构建项目,那将是很好的选择,但这几乎是不可能的。大多数构建都有一些特殊要求,这意味着您需要添加自定义构建逻辑。

Gradle提供了多种机制来扩展它,例如:

  • 自定义任务类型。

当您希望构建完成现有任务无法完成的工作时,只需编写自己的任务类型即可。通常,最好将自定义任务类型的源文件放在buildSrc目录或打包的插件中。然后,您可以像Gradle提供的任何任务一样使用自定义任务类型。

  • 自定义任务动作。

您可以通过Task.doFirst()和Task.doLast()方法附加在任务之前或之后执行的自定义构建逻辑。

  • 项目和任务的额外属性。

这些允许您将自己的属性添加到项目或任务中,然后可以从您自己的自定义操作或任何其他构建逻辑中使用它们。甚至可以将额外的属性应用于您未明确创建的任务,例如Gradle的核心插件创建的任务。

  • 自定义约定。

约定是简化构建的强大方法,因此用户可以更轻松地理解和使用它们。从使用标准项目结构和命名约定的构建(例如Java构建)中可以看出这一点。您可以编写自己的提供约定的插件-它们只需要为构建的相关方面配置默认值。

  • 自定义模型。

Gradle允许您将新概念引入除任务,文件和依赖项配置之外的内部版本。您可以在大多数语言插件中看到这一点,这些插件将源集的概念添加到了构建中。对构建过程进行适当的建模可以大大提高构建的易用性及其效率。

构建脚本针对API运行

将Gradle的构建脚本视为可执行代码很容易,因为它们就是这样。但这只是一个实现细节:精心设计的构建脚本描述了构建软件所需的步骤,而不是这些步骤应如何工作。这是定制任务类型和插件的工作。

人们普遍误认为Gradle的功能和灵活性来自其构建脚本是代码这一事实。这离事实还远。强大的基础模型和API。正如我们在最佳实践中建议的那样,您应该避免在构建脚本中放置太多(如果有的话)命令式逻辑。

然而,在一个区域中,将构建脚本视为可执行代码很有用:了解构建脚本的语法如何映射到Gradle的API。由Groovy DSL参考和Javadocs组成的API文档列出了方法和属性,并引用了闭包和操作。这些在构建脚本的上下文中是什么意思?查看Groovy Build Script Primer,以了解该问题的答案,以便您可以有效地使用API文档。

由于Gradle在JVM上运行,因此构建脚本也可以使用标准Java API。 Groovy构建脚本可以另外使用Groovy API,而Kotlin构建脚本可以使用Kotlin。

总结

通过对 Maven 和Gradle 工作机制的介绍,Maven 程序员对于如何使用 Gradle 有个认知上的提升,Gradle和Maven对如何构建项目有根本不同的视角。 Gradle提供了一个灵活且可扩展的构建模型,该模型将实际工作委托给任务依赖关系图。 Maven使用固定,线性阶段的模型,您可以在其中附加目标(完成工作的事物)。从构架项目这个领域模型来看,有个本质的差别,从而引起架构设计的差异,因此 Maven 程序员必须深刻理解这个差异,提升认知,就可以快速上手。而依赖管理,两个各有千秋,但差异不大。

参考资料

  • Apache Maven 官网:http://maven.apache.org/
  • https://stackoverflow.com/questions/7249871/what-is-a-build-tool
  • https://gradle.org/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值