Ant和Maven之间的差异


180

有人可以告诉我Ant和Maven之间的区别吗?我也从未用过。我知道它们是用来自动构建Java项目的,但是我不知道从哪里开始。


4
由于答案是由Maven倡导者主导的,因此我想稍微加以平衡。看到这个答案,例如stackoverflow.com/questions/1306579/...
切赫Gladkikh

4
虽然这不能直接回答比较Ant与Maven的问题,但我的输入是考虑使用Gradle,它可以使您同时访问Ant和Maven。gradle.org

Answers:


218

在“ Maven:权威指南”中,我在引言中写了有关Maven和Ant之间的区别的部分,标题为“ Ant和Maven之间的区别”。这是一个答案,该答案是该简介中的信息与一些其他说明的结合。

简单比较

我仅向您显示这是为了说明Maven在最基本的层次上具有内置约定的想法。这是一个简单的Ant构建文件:

<project name="my-project" default="dist" basedir=".">
    <description>
        simple example build file
    </description>   
    <!-- set global properties for this build -->   
    <property name="src" location="src/main/java"/>
    <property name="build" location="target/classes"/>
    <property name="dist"  location="target"/>

    <target name="init">
      <!-- Create the time stamp -->
      <tstamp/>
      <!-- Create the build directory structure used by compile -->
      <mkdir dir="${build}"/>   
    </target>

    <target name="compile" depends="init"
        description="compile the source " >
      <!-- Compile the java code from ${src} into ${build} -->
      <javac srcdir="${src}" destdir="${build}"/>  
    </target>

    <target name="dist" depends="compile"
        description="generate the distribution" >
      <!-- Create the distribution directory -->
      <mkdir dir="${dist}/lib"/>

      <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file
-->
      <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
   </target>

   <target name="clean"
        description="clean up" >
     <!-- Delete the ${build} and ${dist} directory trees -->
     <delete dir="${build}"/>
     <delete dir="${dist}"/>
   </target>
 </project>

在这个简单的Ant示例中,您可以看到如何准确地告诉Ant该做什么。有一个编译目标,其中包括javac任务,该任务将src / main / java目录中的源编译为target / classes目录。您必须准确告诉Ant源的位置,想要将结果字节码存储在哪里以及如何将所有这些打包到JAR文件中。尽管最近有一些开发帮助减少了Ant的过程,但是开发人员在Ant方面的经验是对用XML编写的过程语言进行编码。

将之前的Ant示例与Maven示例进行对比。在Maven中,要从某些Java源代码创建JAR文件,您需要做的就是创建一个简单的pom.xml,将源代码放在$ {basedir} / src / main / java中,然后从命令行运行mvn install 。达到相同结果的示例Maven pom.xml。

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.sonatype.mavenbook</groupId>
  <artifactId>my-project</artifactId>
  <version>1.0</version>
</project>

这就是您pom.xml中所需的全部。从命令行运行mvn install将处理资源,编译源代码,执行单元测试,创建JAR并将JAR安装在本地存储库中以在其他项目中重用。无需修改,您可以运行mvn site,然后在target / site中找到一个index.html文件,其中包含指向JavaDoc的链接以及一些有关源代码的报告。

诚然,这是最简单的示例项目。一个仅包含源代码并生成JAR的项目。一个遵循Maven约定并且不需要任何依赖项或自定义项的项目。如果我们要开始自定义行为,则pom.xml的大小将不断增加,在最大的项目中,您会看到非常复杂的Maven POM的集合,其中包含大量的插件自定义和依赖项声明。但是,即使您的项目的POM文件越来越重要,它们所保存的信息也与使用Ant的类似大小的项目的构建文件完全不同。Maven POM包含声明:“这是一个JAR项目”和“源代码在src / main / java中”。Ant构建文件包含明确的指令:“这是项目”,“src/main/java”,“ javac在此目录下运行”,“将结果放入target/classses”,“从...创建一个JAR”等。在必须明确说明该过程的地方,Maven有一些“内置”功能只是知道源代码在哪里以及应该如何处理。

高层比较

在这个例子中,Ant和Maven之间的区别?蚂蚁...

  • 没有像通用项目目录结构这样的正式约定,您必须准确告诉Ant在哪里可以找到源代码以及在哪里放置输出。非正式约定随着时间的流逝而出现,但是尚未将其编入产品中。
  • 是程序上的,您必须确切地告诉Ant该做什么以及何时做。您必须告诉它进行编译,然后复制,然后压缩。
  • 没有生命周期,您必须定义目标和目标依赖性。您必须手动将一系列任务附加到每个目标。

Maven ...

  • 具有约定,它已经知道您的源代码在哪里,因为您遵循了约定。它将字节码放入目标/类中,并在目标中产生了一个JAR文件。
  • 是声明性的。您要做的就是创建一个pom.xml文件,并将源文件放在默认目录中。Maven负责其余的工作。
  • 有一个生命周期,您在执行时会调用它mvn install。该命令告诉Maven执行一系列序列步骤,直到到达生命周期。作为整个生命周期过程的副作用,Maven执行了许多默认插件目标,这些目标做了诸如编译和创建JAR之类的事情。

那常春藤呢?

是的,所以像史蒂夫·拉夫兰(Steve Loughran)这样的人将阅读该比较报告并称犯规。他将谈论答案如何完全忽略Ivy,以及Ant可以在最新版的Ant中重用构建逻辑这一事实。这是真的。如果您有一群聪明的人使用Ant + antlibs + Ivy,那么您将得到一个设计良好且有效的构建。即使我非常相信Maven很有道理,但我很乐意将Ant + Ivy与一个拥有非常精明的构建工程师的项目团队一起使用。话虽这么说,但我确实认为您最终会错过许多有价值的插件,例如Jetty插件,并且最终将完成大量不必要的工作。

比Maven vs.Ant更重要

  1. 是您使用存储库管理器来跟踪软件工件。我建议下载Nexus。您可以使用Nexus代理远程存储库,并为您的团队提供部署内部工件的场所。
  2. 您已经对软件组件进行了适当的模块化。一个大的整体组件很少随时间扩展。随着项目的发展,您将需要具有模块和子模块的概念。Maven非常适合这种方法。
  3. 您采用一些约定进行构建。即使您使用Ant,也应努力采用与其他项目一致的某种形式的约定。当一个项目使用Maven时,这意味着熟悉Maven的任何人都可以选择构建并开始运行它,而不必费心配置就可以弄清楚如何进行编译。

1
链接再次断开。
Thunderforge 2014年

1
我使用Nebeans,Ant在默认情况下没有任何调整(Netbeans约定?)。当前尝试使用Maven,并在首次构建期间发现它的时间更长,并不断使用Internet连接。离线构建可能是不可能的。这很不舒服。
Zon

113

Maven是框架,Ant是工具箱

Maven是预制的公路车,而Ant是一组汽车零件。使用蚂蚁,您必须制造自己的汽车,但是至少如果您需要进行越野驾驶,则可以制造正确类型的汽车。

换句话说,Maven是一个框架,而Ant是一个工具箱。如果您对在框架范围内工作感到满意,那么Maven会做的很好。对我来说,问题在于我不断碰到框架的界限,而且不会让我失望。

XML详尽度

tobrien是一个非常了解Maven的人,我认为他对这两种产品进行了很好的诚实比较。他将简单的Maven pom.xml与简单的Ant构建文件进行了比较,并提到了Maven项目如何变得更加复杂。我认为值得一看一下您在一个简单的实际项目中可能会看到的几个文件的比较。以下文件表示多模块构建中的单个模块。

首先,Maven文件:

<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 http://maven.apache.org/maven-4_0_0.xsd">

    <parent>
        <groupId>com.mycompany</groupId>
        <artifactId>app-parent</artifactId>
        <version>1.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>persist</artifactId>
    <name>Persistence Layer</name>

    <dependencies>

        <dependency>
            <groupId>com.mycompany</groupId>
            <artifactId>common</artifactId>
            <scope>compile</scope>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>com.mycompany</groupId>
            <artifactId>domain</artifactId>
            <scope>provided</scope>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>${hibernate.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>${commons-lang.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
            <version>${spring.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.dbunit</groupId>
            <artifactId>dbunit</artifactId>
            <version>2.2.3</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
            <classifier>jdk15</classifier>
        </dependency>

        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>${commons-dbcp.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc</artifactId>
            <version>${oracle-jdbc.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.easymock</groupId>
            <artifactId>easymock</artifactId>
            <version>${easymock.version}</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

和等效的Ant文件:

<project name="persist" >

    <import file="../build/common-build.xml" />


    <path id="compile.classpath.main">
        <pathelement location="${common.jar}" />
        <pathelement location="${domain.jar}" />
        <pathelement location="${hibernate.jar}" />
        <pathelement location="${commons-lang.jar}" />
        <pathelement location="${spring.jar}" />
    </path>


    <path id="compile.classpath.test">
        <pathelement location="${classes.dir.main}" />
        <pathelement location="${testng.jar}" />
        <pathelement location="${dbunit.jar}" />
        <pathelement location="${easymock.jar}" />
        <pathelement location="${commons-dbcp.jar}" />
        <pathelement location="${oracle-jdbc.jar}" />
        <path refid="compile.classpath.main" />
    </path>


    <path id="runtime.classpath.test">
        <pathelement location="${classes.dir.test}" />
        <path refid="compile.classpath.test" />
    </path>


</project>

tobrien用他的例子表明Maven具有内置的约定,但这并不一定意味着您最终减少了XML的编写。我发现相反的说法是正确的。pom.xml的长度是build.xml的3倍,并且没有违反约定。实际上,显示的我的Maven示例没有额外的54行来配置插件。该pom.xml用于一个简单的项目。当您开始添加额外的需求时,XML确实开始显着增长,这在许多项目中并不少见。

但是你必须告诉蚂蚁怎么办

我上面的Ant示例当然是不完整的。我们仍然必须定义用于清理,编译,测试等的目标。这些目标是在通用构建文件中定义的,该文件由多模块项目中的所有模块导入。这使我想到了所有这些东西都必须在Ant中显式编写而在Maven中是声明性的。

的确如此,如果我不必显式编写这些Ant目标,它将为我节省时间。但是多少时间?我现在使用的通用构建文件是我5年前编写的文件,此后仅作了一些细化。在对Maven进行2年的实验后,我将旧的Ant构建文件从壁橱中取出,除掉了灰尘,然后重新使用。对我来说,在5年的时间里,必须明确告诉Ant要做的事情加起来不到一周。

复杂

我要提及的下一个主要区别是复杂性及其所产生的现实效果。Maven的构建旨在减少负责创建和管理构建过程的开发人员的工作量。为此,它必须很复杂。不幸的是,这种复杂性往往会否定其预期目标。

与Ant相比,Maven项目的构建人员将花费更多时间:

  • 阅读文档:关于Maven的文档更多,因为您需要学习的内容太多。
  • 对团队成员进行教育:他们发现,问一个认识的人比尝试自己找到答案更容易。
  • 对构建进行故障诊断:Maven不如Ant可靠,尤其是非核心插件。而且,Maven构建不可重复。如果您很可能依赖于SNAPSHOT版本的插件,则无需更改任何内容即可中断构建。
  • 编写Maven插件:编写插件时通常要考虑到特定的任务,例如创建Webstart捆绑包,这使得将它们重用于其他任务或将它们组合以实现目标变得更加困难。因此,您可能必须编写自己的解决方案,以解决现有插件集中的空白。

相反:

  • 蚂蚁文档简明,全面,一站式提供。
  • 蚂蚁很简单。尝试学习Ant的新开发人员仅需要了解一些简单的概念(目标,任务,依赖项,属性),以便能够弄清他们需要知道的其他内容。
  • 蚂蚁是可靠的。过去几年来没有太多的Ant版本,因为它已经可以使用了。
  • Ant构建是可重复的,因为它们通常是在没有任何外部依赖项的情况下创建的,例如在线存储库,实验性第三方插件等。
  • 蚂蚁很全面。因为它是一个工具箱,所以您可以组合工具来执行几乎所有想要的任务。如果您需要编写自己的自定义任务,则非常简单。

熟识

另一个区别是熟悉度。新的开发人员总是需要时间来加快速度。熟悉现有产品在这方面有帮助,Maven支持者正确地声称这是Maven的好处。当然,Ant的灵活性意味着您可以创建自己喜欢的约定。因此,我使用的约定是将源文件放在目录名称src / main / java中。我编译的类进入名为target / classes的目录。听起来很熟悉,不是吗。

我喜欢Maven使用的目录结构。我认为这是有道理的。也是他们的构建生命周期。因此,我在Ant构建中使用了相同的约定。不仅因为它有意义,而且因为以前使用过Maven的任何人都会熟悉它。


7
我真的很喜欢您如何“窃取” Maven的想法并将其应用到您的Ant构建中,以遵循常见的约定并使其他人更容易过渡。
IgorČordaš2014年

为了避免pom.xmls出现膨胀,我通过XSLT生成了其中的大多数。
Demi

21

Ant主要是一个构建工具。

Maven是一个项目和依赖项管理工具(当然也可以构建您的项目)。

如果您想避免使用Maven,则Ant + Ivy是很好的组合。


这个。这里比较Ant + Ivy和Maven2:ant.apache.org/ivy/m2comparison.html
Esko,2009年

为什么要避免使用Maven?以我的经验,Maven是令人愉悦的Java开发的少数​​部分之一。
本森

4
@本森:这是一个有争议的问题。如果这是灵丹妙药,那么每个人都会使用它。
cherouvim

18

仅列出更多差异:

  • 蚂蚁没有正式的约定。您必须准确告诉Ant在哪里可以找到源,在哪里放置输出等。
  • 蚂蚁是程序性的。您必须准确地告诉Ant该怎么做。告诉它进行编译,复制然后压缩等。
  • 蚂蚁没有生命周期。
  • Maven使用约定。只要遵循这些约定,它就会知道源代码自动在哪里。您无需告诉Maven它在哪里。
  • Maven是声明性的;您所需要做的就是创建一个pom.xml文件,并将您的源代码放在默认目录中。Maven将负责其余的工作。
  • Maven具有生命周期。您只需调用mvn install,然后执行一系列序列步骤。
  • Maven具有有关常见项目任务的情报。要运行测试,只需执行mvn test,只要文件位于默认位置即可。在Ant中,您首先需要创建JUnit JAR文件,然后创建一个包含JUnit JAR的类路径,然后告诉Ant应该在哪里寻找测试源代码,编写一个目标来编译测试源,然后最终执行单元测试。使用JUnit。

更新:

这来自《Maven:权威指南》。抱歉,我完全忘了引用它。


那是双关语吗?
vakio

1
@vakio-我猜你的意思是因为我使用“站点”而不是“引用”?这对我来说完全是一个错误的拼写,我
已将

17

Maven还是Ant?与这个问题非常相似,应该可以帮助您回答问题。

什么是Maven?在官方网站上。

编辑:对于一个新的/未开发的项目,我建议使用Maven:“约定之上的配置”将为您节省编写和设置构建和部署脚本的大量时间。当您使用ant时,构建脚本的长度和复杂度会随着时间的增长而增长。对于现有项目,很难将其配置/布局插入Maven系统。


Maven可以在项目开始时为您节省时间,但是随着时间的流逝,如果您除了一个非常简单的项目之外还拥有其他任何东西,那么Maven脚本将比与Ant等效的脚本变得更加复杂。例如,查看Maven Assembly插件。
凯文·斯特布里奇

我认为,以Maven格式(您以xml格式布置装配体的模型)来完成Assembly插件的工作要比在Ant中完成所有手动步骤要容易得多,但是YMMV
matt b

嗨,马特,程序集插件的学习曲线比Ant tar或zip任务的学习曲线陡峭得多。描述符格式大约有150行,其中包含一堆非直观的配置选项。最重要的是,它不起作用!在这一点上,我放弃了Assembly插件,对unpack的筛选不起作用,文件模式选项也不起作用,并且无法fixcrlf。不确定“ Ant中的所有手动步骤”是什么意思。我花了大约5分钟的时间让Ant进行了数小时无法完成的组装插件工作。
凯文·斯特布里奇

3
第一条链接现在已经死了:/
Matt Clark

15

Maven既充当依赖性管理工具(可用于从中央存储库或您设置的存储库中检索jar),又充当声明性构建工具。“声明式”构建工具与更传统的构建工具(例如ant或make)之间的区别在于,您需要配置需要完成的工作,而不是如何完成工作。例如,您可以在Maven脚本中说应该将项目打包为WAR文件,而Maven知道如何处理。

Maven依赖于有关如何布置项目目录的约定,以实现其“声明性”。例如,它有一个约定,约定将主代码放置在哪里,将web.xml放置在何处,进行单元测试等等,但是如果需要,还可以更改它们。

您还应该记住,有一个插件可以在maven中运行ant命令:

http://maven.apache.org/plugins/maven-ant-plugin/

同样,Maven的原型使项目的入门变得非常快。例如,有一个Wicket原型,它提供了您运行的maven命令来获取一个完整的,随时可运行的hello世界类型的项目。

https://wicket.apache.org/start/quickstart.html


11

我可以带一个从未见过蚂蚁的人- build.xml的语言写得不错-并且他们可以了解发生了什么。我可以带那个人给他们看一个Maven POM,他们不会知道发生了什么。

在庞大的工程组织中,人们会写关于Ant文件变得庞大且难以管理的文章。我已经写了那些类型清理了Ant脚本。真正了解您需要做什么,并设计一套可以在3年以上的时间内响应变化和扩展的模板。

除非您有一个简单的项目,否则要学习Maven约定和Maven完成工作的方式,需要做很多工作。

归根结底,您不能将使用Ant或Maven启动项目视为一个因素:这实际上是总拥有成本。组织在几年内维护和扩展其构建系统所需要的是必须考虑的主要因素之一。

构建系统最重要的方面是依赖性管理和表达构建配方的灵活性。如果做得好,它必须有点直观。


6

我会说这取决于您项目的大小...就个人而言,我会将Maven用于需要直接编译,打包和部署的简单项目。一旦您需要做一些更复杂的事情(许多依赖项,创建映射文件...),我将切换到Ant ...


我不同意。我同意将Maven用于简单项目是很好的,但是我认为随着Maven的增加,使用Maven的收益将增加几个数量级。
本森

我也不同意,当您的系统更复杂且包含许多相互关联的模块时,Maven确实可以开始正常工作。如果您需要编写功能测试,运行报告并将工件部署到存储库管理器,那么为什么要使用Ant自己完成所有这些工作?
蒂姆·奥布莱恩

Maven对于一个简单的项目来说是很好的选择,但是我在做一个复杂的项目中应该做的简单的事情时遇到了噩梦。例如,创建可分发的软件包,混淆代码,创建Webstart捆绑包,配置配置文件。@Benson,随着您的项目变得越来越复杂,Maven变成了一个球。与Maven相比,Ant的强大功能和灵活性将为您带来更大的生产率收益。@ tobrien,Ant适用于多模块项目,编写功能测试等。在Maven中配置非默认报告插件通常比同等的Ant更冗长。
凯文·斯坦布里奇

我刚刚开始将Maven添加到现有项目中,但发现事情没有按预期进行。该网站使用php构建,并使用脚本进行部署。这些事情在Maven中无法正常运行,您必须做一些非常奇怪的事情才能使其工作。
罗尔·卢纳

4

Maven还包含一个大型的常用开源项目存储库。在构建期间,Maven可以为您下载这些依赖项(以及您的依赖项依赖项:)),以使构建项目的这一部分更易于管理。


2
+1,已经了解了保持Central Maven信息库正常运行所需的一切,我不得不插话,建议使用Maven和Ivy之类的任何人都应该考虑安装信息库管理器。哪一个都不重要,但是我偏爱Nexus nexus.sonatype.org
蒂姆·奥布莱恩
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.