Java构建工具:Ant vs. Maven vs Gradle

最初,Make是唯一可用的构建工具。 后来通过GNU Make进行了改进。 但是,从那时起,我们的需求增加了,结果,构建工具也不断发展。

JVM生态系统主要由三个构建工具组成:

  • 常春藤的 Apache Ant
  • 马文
  • 摇篮

蚂蚁 Ant是“现代”构建工具中的第一个。 在许多方面,它类似于Make。 它于2000年发布,并在短时间内成为Java项目最受欢迎的构建工具。 它的学习曲线非常低,因此任何人都可以在无需任何特殊准备的情况下开始使用它。 它基于过程编程思想。

最初发行后,它通过接受插件的功能得到了改进。

主要缺点是将XML作为编写构建脚本的格式。 XML本质上是分层的,因此不适合Ant使用的过程编程方法。 Ant的另一个问题是,与非常小的项目一起使用时,其XML往往变得难以管理。

后来,由于必须通过网络进行依赖管理,Ant采用了Apache Ivy 。

Ant的主要好处是对构建过程的控制。

专家 Maven于2004年发布。其目标是改善开发人员在使用Ant时面临的一些问题。

Maven继续使用XML作为编写构建规范的格式。 但是,结构截然不同。 尽管Ant要求开发人员编写所有导致成功执行某些任务的命令,但Maven依赖于约定并提供了可以调用的可用目标(目标)。 作为附加的,可能也是最重要的附加功能,Maven引入了通过网络下载依赖项的功能(后来由Ant通过Ivy采纳)。 这本身就彻底改变了我们交付软件的方式。

但是,Maven有其自身的问题。 依赖关系管理不能很好地处理同一库的不同版本之间的冲突(Ivy更擅长于此)。 XML作为构建配置格式经过严格的结构化和高度标准化。 目标(目标)的定制很难。 由于Maven主要关注于依赖关系管理,因此,与在Ant中相比,在Maven中编写复杂,自定义的构建脚本实际上更加困难。

用XML编写的Maven配置连续又繁琐。 在较大的项目中,它可以具有数百行代码,而无需实际执行“非凡”的工作。

Maven的主要好处是其生命周期。 只要该项目基于某些标准,就可以使用Maven相对轻松地贯穿整个生命周期。 这是以灵活性为代价的。

同时,对DSL(特定领域语言)的兴趣持续增长。 这个想法是让语言被设计用来解决属于特定领域的问题。 在构建的情况下,应用DSL的结果之一就是Gradle。

摇动 Gradle结合了这两种工具的优点,并在它们之上进行了DSL和其他改进。 它具有Ant的功能和灵活性,并具有Maven的生命周期和易用性。 最终结果是该工具于2012年发布,并在短时间内引起了广泛关注。 例如,谷歌采用Gradle作为Android OS的默认构建工具。

Gradle不使用XML。 相反,它具有基于Groovy (JVM语言之一)的自己的DSL。 结果,Gradle构建脚本往往比为Ant或Maven编写的脚本更短,更清晰。 Gradle的样板代码量要少得多,因为它的DSL是为解决特定问题而设计的:在软件的整个生命周期中移动软件,从编译到静态分析和测试,再到打包和部署。

它使用Apache Ivy来满足JAR依赖关系。

摇摇晃晃的努力可以总结为“聚会好,灵活性也好”。

代码示例

我们将创建构建脚本,这些脚本将进行编译,执行静态分析,运行单元测试以及最终创建JAR文件。 我们将在所有三个框架(Ant,Maven和Gradle)中进行这些操作,并比较语法。 通过比较每个任务的代码,我们将能够更好地理解差异并就构建工具的选择做出明智的决定。

首先是第一件事。 如果您要自己完成本文中的示例,则需要安装Ant , Ivy , Maven和Gradle 。 请按照这些工具制造商提供的安装说明进行操作。 您可以选择不自己运行示例,而完全跳过安装。 代码段应该足以使您了解每种工具的工作原理。

代码存储库https://github.com/vfarcic/JavaBuildTools包含Java代码(两个带有相应测试的简单类),checkstyle配置以及Ant,Ivy,Maven和Gradle配置文件。

让我们从Ant和Ivy开始。

蚂蚁与常春藤

常春藤依赖项需要在ivy.xml文件中指定。 我们的示例非常简单,仅需要JUnit和Hamcrest依赖项。

[ ivy.xml ]

<ivy-module version="2.0"><info organisation="org.apache" module="java-build-tools"/><dependencies><dependency org="junit" name="junit" rev="4.11"/><dependency org="org.hamcrest" name="hamcrest-all" rev="1.3"/></dependencies>
</ivy-module>

现在,我们将创建我们的Ant构建脚本。 它的任务只是编译一个JAR文件。 最终结果是以下build.xml。

[ build.xml ]

<project xmlns:ivy="antlib:org.apache.ivy.ant" name="java-build-tools" default="jar"><property name="src.dir" value="src"/><property name="build.dir" value="build"/><property name="classes.dir" value="${build.dir}/classes"/><property name="jar.dir" value="${build.dir}/jar"/><property name="lib.dir" value="lib" /><path id="lib.path.id"><fileset dir="${lib.dir}" /></path><target name="resolve"><ivy:retrieve /></target><target name="clean"><delete dir="${build.dir}"/></target><target name="compile" depends="resolve"><mkdir dir="${classes.dir}"/><javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="lib.path.id"/></target><target name="jar" depends="compile"><mkdir dir="${jar.dir}"/><jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"/></target></project>

首先,我们指定几个属性。 从那里开始,一项任务接another而至。 我们使用Ivy来解决依赖关系,清理,编译并最终创建JAR文件。 几乎每个Java项目都需要执行的任务需要大量的配置。

要运行创建JAR文件的Ant任务,请执行以下操作。

ant jar

让我们看看Maven将如何执行相同的任务集。

马文

[ pom.xml ]

<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.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.technologyconversations</groupId><artifactId>java-build-tools</artifactId><packaging>jar</packaging><version>1.0</version><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version></dependency><dependency><groupId>org.hamcrest</groupId><artifactId>hamcrest-all</artifactId><version>1.3</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version></plugin></plugins></build></project>

要运行创建JAR文件的Maven目标,请执行以下操作。

mvn package

主要区别在于,使用Maven,我们不需要指定应该做什么。 我们不是在创建任务,而是在设置参数(依赖项是什么,要使用哪些插件……)。 这显示了Ant和Maven之间的主要区别。 后来提倡使用约定,并提供现成的目标(目标)。 随着时间的流逝,Ant和Maven XML文件都会变得越来越大。 为了说明这一点,我们将添加Maven CheckStyle,FindBugs和PMD插件,这些插件将负责静态分析。 这三个都是相当标准的工具,在许多Java项目中都以一种或另一种形式使用。 我们希望将所有静态分析作为单个目标的一部分与单元测试一起进行验证 。 此外,我们应指定自定义checkstyle配置的路径,并确保其在出错时失败。 其他Maven代码如下:

[ pom.xml ]

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-checkstyle-plugin</artifactId><version>2.12.1</version><executions><execution><configuration><configLocation>config/checkstyle/checkstyle.xml</configLocation><consoleOutput>true</consoleOutput><failsOnError>true</failsOnError></configuration><goals><goal>check</goal></goals></execution></executions>
</plugin>
<plugin><groupId>org.codehaus.mojo</groupId><artifactId>findbugs-maven-plugin</artifactId><version>2.5.4</version><executions><execution><goals><goal>check</goal></goals></execution></executions>
</plugin>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-pmd-plugin</artifactId><version>3.1</version><executions><execution><goals><goal>check</goal></goals></execution></executions>
</plugin>

要运行使用CheckStyle,FindBugs和PMD运行单元测试和静态分析的Maven目标,请执行以下命令。

mvn verify

我们必须编写许多XML,这些XML可以完成一些非常基本且常用的任务集。 在具有更多依赖项和任务的真实项目中,Maven pom.xml文件可以轻松到达数百甚至数千行XML。

这是Gradle中的外观。

摇篮

[ build.gradle ]

apply plugin: 'java'
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'version = '1.0'repositories {mavenCentral()
}dependencies {testCompile group: 'junit', name: 'junit', version: '4.11'testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
}

Gradle代码不仅比Maven短得多,而且对熟悉Gradle的人来说比Maven更容易理解,而且实际上引入了许多有用的任务,而这些正是我们刚刚编写的Maven代码所没有的。 要获取Gradle可以使用当前配置运行的所有任务的列表,请执行以下操作。

gradle tasks --all

清晰度,复杂性和学习曲线

对于新手来说,Ant是所有工具中最清晰的工具。 只需阅读配置XML,就可以了解它的作用。 但是,编写Ant任务很容易变得非常复杂。 Maven,特别是Gradle,具有许多现成可用的或通过插件提供的任务。 例如,通过看下面的一行,对于那些不了解Gradle之谜的人来说可能不清楚,哪些任务将被解锁以供我们使用。

[build.gradle]

apply plugin: 'java'

这行简单的代码添加了20多个任务,等待我们使用。

在我看来,Ant的可读性和Maven的简单性是错误的论点,它们仅在短暂的最初Gradle学习曲线中适用。 一旦使用了Gradle DSL,它的语法就会比Ant或Maven使用的语法更短,更容易理解。 而且,只有Gradle提供约定和命令创建。 尽管可以用Ant任务扩展Maven,但它很乏味且效率不高。 Groovy的Gradle将其提升到一个新的水平。

下一篇文章将更深入地介绍Gradle,并更详细地说明其与Groovy的集成。

翻译自: https://www.javacodegeeks.com/2014/06/java-build-tools-ant-vs-maven-vs-gradle.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363823.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Asp.Net中用javascript实现弹出窗口永远居中

//Asp.Net中用javascript实现弹出窗口永远居中functionShowDialog(url) { var iWidth600; //模态窗口宽度 var iHeight500;//模态窗口高度 var iTop(window.screen.height-iHeight)/2; var iLeft(window.screen.width-iWidth)/2; window.open(url,"Detail"…

Linux Vim 光标错位,技术|Vim 复制粘帖格式错乱问题的解决办法

有时候&#xff0c;复制文本(尤其是代码)到 Vim&#xff0c;会出现格式错乱的问题。看样子&#xff0c;应该是自动缩进惹得祸。本文不去深究原因&#xff0c;直接给出解决方法。1. paste 模式运行如下命令&#xff0c;进入 paste 模式&#xff1a;:set paste进入 paste 模式后&…

kali vmtools 不能复制粘贴解决方法(绝对实用)

朋友问起怎么vm kali 2019怎么不能复制了&#xff0c;而且网上的方法大多不适合。我就在这儿记录一笔吧&#xff0c;方便大家。 之前发现最新kali复制粘贴不能用&#xff0c;后来发现一个奇妙的套路&#xff0c;不是共享文件夹。只需要把文件复制到命令行中&#xff0c;会出现t…

MineCraft和堆外内存

总览 MineCraft是一个很好的例子&#xff0c;说明何时堆外内存确实可以提供帮助。 关键要求是&#xff1a; 保留的数据大部分是一个简单的数据结构&#xff08;在我的世界的情况下&#xff0c;它的很多字节[]&#xff09; 堆外内存的使用可以隐藏在抽象中。 考试 我使用以下测…

kubernetes进阶之七:Service

1.概述 Service也是Kubernetes里的最核心的资源对象之一&#xff0c;Kubernetes里的每个Service其实就是我们经常提起的微服务架构中的一个“微服务”&#xff0c;之前我们所说的Pod、RC等资源对象其实都是为这节所说的“服务”------Kubernetes Service作“嫁衣”的。图1.12显…

Json Schema的使用

直接上案例&#xff1a; 在Web Api通讯中&#xff0c;客户端发送json数据&#xff0c;服务端反序列化json&#xff08;json与某个类形成对应关系&#xff09;&#xff0c;在某些情况下&#xff0c;需要校验其上传的json是否合法。 服务端是使用Json.net(newtonsoft.json)进行…

红帽企业版linux 7.4更新启动,红帽Linux企业版7.4 淘汰Btrfs文件系统

我们不得不承认Btrfs是一种古老的文件系统&#xff0c;当初(2007年)是由甲骨文宣布并进行中的COW(copy-on-write式)文件系统&#xff0c;意图取代Linux的ext。但是天不遂人愿&#xff0c;2011年8月9日&#xff0c;Fedora就决定Btrfs不再作为Fedora 16默认文件系统&#xff0c;走…

关于控件postback 后viewstate加载失败的问题

我写了一个控件Inherits TextBox&#xff0c;里面有一个复杂属性Tip&#xff0c;但每次postback的时候都说加载viewstate失败&#xff0c;除非我在!postback的情况下给Tip.xxx赋值. 下面我贴出代码&#xff0c;我已经搞了一天了&#xff0c;搞不出什么原因。 JTextBox控件 usin…

天猫浏览型应用的CDN静态化架构演变(转)

在天猫双11活动中&#xff0c;商品详情、店铺等浏览型系统&#xff0c;通常会承受超出日常数倍甚至数十倍的流量冲击。随着历年来双11流量的大幅增加&#xff0c;每年这些浏览型 系统都要面临容量评估、硬件扩容、性能优化等各类技术挑战。因此&#xff0c;架构方面的重点在于&…

查看您的Solr缓存大小:Eclipse Memory Analyzer

Solr使用不同的缓存来防止请求期间过多的IO访问和计算。 当索引不是很频繁发生时&#xff0c;您可以通过使用这些缓存来获得巨大的性能提升。 根据索引数据的结构和缓存的大小&#xff0c;它们可能会变得很大&#xff0c;并占用堆内存的很大一部分。 在本文中&#xff0c;我想展…

会话跟踪之Session

Session是服务端使用记录客户端状态的一种机制&#xff0c;Session使用简单&#xff0c;但是和Cookie相比&#xff0c;增加了服务器的存储压力【因为为了追求速度&#xff0c;服务器将Session放置在了内存中】。Cookie是保存在客户端的&#xff0c;然而Session是保存在服务器上…

在NIO.2中创建文件和目录

如今&#xff0c;大量的应用程序创建文件或目录的目的非常广泛。 无论是生成报告&#xff0c;导出配置文件还是仅存储一些数据&#xff0c;能够处理这些任务都非常重要。 创建文件和目录是使用文件系统时最常用的功能之一。 图书馆的这一部分进行了相当现代化。 这方面的更新包…

实现flash的图片切换效果【可以切换多个网页或者图片】

这个是得到改进后的代码&#xff0c;可以切换多个页面 需要完整代码的朋友可以留下email如需再添加切换页面&#xff0c;只要按照下边代码部分的样式添加内容即可切换导航td的id要顺序排那个div的TOP为为上边一个div的Top加上div本身的高度&#xff1a;2371<% Page Language…

《SpringMVC从入门到放肆》三、DispatcherServlet的url-pattern配置详解

上一篇我们详细解释了一下SrpingMVC的执行流程以及一些默认的配置&#xff0c;在Spring的思想中&#xff0c;就是默认大于配置。今天我们来详细的研究一下DispatcherServlet的url-pattern配置。 一、DispatcherServlet的url-pattern配置在没有特别要求的情况下&#xff0c;Spri…

vc中怎么使用SendMessage自定义消息函数

vc中怎么使用SendMessage自定义消息函数&#xff1a; SendMessage的基本结构如下&#xff1a; SendMessage( HWND hWnd, //消息传递的目标窗口或线程的句柄。 UINT Msg, //消息类别&#xff08;这里可以是一些系统消息&#xff0c;也可以是自己定义&#xff0c;下文具…

多路复用IO和异步IO

多路复用I/O 它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket&#xff0c;当某个socket有数据到达了&#xff0c;就通知用户进程。 流程图如下&#xff1a; 当用户进程调用了select&#xff0c;那么整个进程会被block&#xff0c;而同时&#xff0c…

Java开发人员应该知道的7种新工具

通过快速浏览一些最新的创新工具&#xff0c;随时准备锁定和加载。 万一您错过了它&#xff0c;RebelLabs最近发布了Java工具和技术前景的全球调查结果 。 除了著名的工具和成熟的工具外&#xff0c;市场还涌现出鲜有人知的新鲜工具和框架。 在这篇文章中&#xff0c;我决定收集…

leetcode-92-反转链表②

题目描述&#xff1a; 方法一: class Solution:def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:dummy ListNode(0)dummy.next headpre dummyfor i in range(m-1):pre pre.nextstart pre.nexttrail start.nextfor i in range(n-m):start.next …

linux 7 services设定,CENTOS/RHEL7系统中设置SYSTEMD SERVICE的ULIMIT资源限制

8种机械键盘轴体对比本人程序员&#xff0c;要买一个写代码的键盘&#xff0c;请问红轴和茶轴怎么选&#xff1f;在bash中&#xff0c;有个ulimit命令&#xff0c;提供了对shell及该shell启动的进程的可用资源控制。主要包括打开文档描述符数量、用户的最大进程数量、coredump文…

ON_COMMAND_RANGE用法

afx_msg voidOnOutPutStatusButtonUp (WPARAM wParam, LPARAM lParam);BEGIN_MESSAGE_MAP(CIOStatue, CDialog)//{{AFX_MSG_MAP(CIOStatue)//}}AFX_MSG_MAPON_COMMAND_RANGE(IDC_STATIC_OUT1,IDC_STATIC_OUT16,OnOutPutStatusButtonUp)END_MESSAGE_MAP()//注意IDC_STATIC_OUT1…