ChatGPT解决这个技术问题 Extra ChatGPT

Ant和Maven之间的差异[关闭]

关闭。这个问题需要更加集中。它目前不接受答案。想改进这个问题?更新问题,使其仅通过编辑此帖子专注于一个问题。 8年前关闭。改进这个问题

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

由于答案由 Maven 倡导者主导,我想稍微平衡一下。请参阅此答案,例如 stackoverflow.com/questions/1306579/…
虽然这并不能直接回答比较 Ant 与 Maven 的问题,但我的意见是使用 Gradle,它可以让您同时访问 Ant 和 Maven。 gradle.org

h
hjpotter92

Maven: The Definitive Guide 中,我在简介中写了 Maven 和 Ant 之间的区别,部分标题是 "The Differences Between Ant and 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 要做什么。有一个编译目标,其中包括将 src/main/java 目录中的源代码编译到 target/classes 目录的 javac 任务。您必须准确地告诉 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”、“从 . ...”等。Ant 必须明确说明该过程,而 Maven 有一些“内置”的东西,它只知道源代码在哪里以及应该如何处理它。

高级比较

这个例子中 Ant 和 Maven 的区别?蚂蚁...

没有像通用项目目录结构这样的正式约定,您必须准确地告诉 Ant 在哪里可以找到源代码以及在哪里放置输出。随着时间的推移,非正式的约定已经出现,但它们还没有被编入产品中。

是程序性的,你必须准确地告诉 Ant 做什么以及什么时候做。你必须告诉它编译,然后复制,然后压缩。

没有生命周期,您必须定义目标和目标依赖项。您必须手动将一系列任务附加到每个目标。

马文在哪里...

有约定,它已经知道你的源代码在哪里,因为你遵循了约定。它将字节码放在目标/类中,并在目标中生成一个 JAR 文件。

是声明性的。您所要做的就是创建一个 pom.xml 文件并将您的源代码放在默认目录中。 Maven 负责其余的工作。

有一个生命周期,您在执行 mvn install 时调用它。该命令告诉 Maven 执行一系列序列步骤,直到它到达生命周期。作为整个生命周期旅程的副作用,Maven 执行了许多默认插件目标,这些目标执行诸如编译和创建 JAR 之类的事情。

常春藤呢?

是的,所以像史蒂夫拉夫兰这样的人会读到这个比较并吹犯规。他将讨论答案如何完全忽略了称为 Ivy 的东西,以及 Ant 可以在最新版本的 Ant 中重用构建逻辑的事实。这是真实的。如果您有一群聪明的人使用 Ant + antlibs + Ivy,那么您最终会得到一个设计良好且有效的构建。尽管如此,我非常确信 Maven 是有意义的,但我很乐意将 Ant + Ivy 与一个拥有非常敏锐的构建工程师的项目团队一起使用。话虽如此,我确实认为您最终会错过许多有价值的插件,例如 Jetty 插件,并且您最终会做一大堆您不需要随着时间的推移做的工作。

比 Maven vs. Ant 更重要

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


链接又断了。
我默认使用 Nebeans 和 Ant 工作,没有任何调整(Netbeans 约定?)。目前正在尝试 Maven,发现它在第一次构建和不断使用互联网连接期间更长。离线构建可能是不可能的。这很不舒服。
K
KevinS

Maven 是一个框架,Ant 是一个工具箱

Maven 是一辆预制的公路车,而 Ant 是一套汽车零件。使用 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 示例并不完整。我们仍然需要定义用于清理、编译、测试等的目标。这些目标是在一个通用构建文件中定义的,该文件由多模块项目中的所有模块导入。这让我明白了所有这些东西必须在 Ant 中显式编写,而在 Maven 中是声明性的。

的确,如果我不必显式编写这些 Ant 目标,它会节省我的时间。但是多少时间?我现在使用的通用构建文件是我 5 年前编写的,从那时起只做了轻微的改进。在我对 Maven 进行了 2 年的实验之后,我将旧的 Ant 构建文件从壁橱里拿出来,掸掉了灰尘,然后重新开始工作。对我来说,在 5 年的时间里,必须明确告诉 Ant 做什么的成本加起来不到一周。

复杂

我想提到的下一个主要区别是复杂性及其对现实世界的影响。构建 Maven 的目的是减少负责创建和管理构建过程的开发人员的工作量。为了做到这一点,它必须很复杂。不幸的是,这种复杂性往往会否定他们的预期目标。

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

阅读文档:关于 Maven 的文档要多得多,因为你需要学习的东西还有很多。

教育团队成员:他们发现向知道的人提问比自己寻找答案更容易。

构建故障排除:Maven 不如 Ant 可靠,尤其是非核心插件。此外,Maven 构建是不可重复的。如果您依赖于插件的 SNAPSHOT 版本,这很可能,您的构建可能会在您没有更改任何内容的情况下中断。

编写 Maven 插件:插件通常在编写时考虑到特定的任务,例如创建一个 webstart 包,这使得将它们重用于其他任务或将它们组合以实现目标变得更加困难。因此,您可能必须编写自己的一个来解决现有插件集中的空白。

相比之下:

Ant 文档简洁、全面且集中在一处。

蚂蚁很简单。尝试学习 Ant 的新开发人员只需要了解一些简单的概念(目标、任务、依赖项、属性),就能够弄清楚他们需要了解的其余内容。

蚂蚁是可靠的。在过去的几年里,Ant 的发布并不多,因为它已经可以工作了。

Ant 构建是可重复的,因为它们通常是在没有任何外部依赖项的情况下创建的,例如在线存储库、实验性第三方插件等。

蚂蚁是全面的。因为它是一个工具箱,所以您可以组合这些工具来执行几乎任何您想要的任务。如果您需要编写自己的自定义任务,这很简单。

熟悉度

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

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


我真的很喜欢你如何从 Maven 中“窃取”想法并将它们应用到你的 Ant 构建中,以遵循常见的约定并使其他人的过渡更容易。
为了避免在 pom.xml 中膨胀,我通过 XSLT 生成其中的大部分。
c
cherouvim

Ant主要是一个构建工具。

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

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


这个。 Ant+Ivy 和 Maven2 的比较在这里:ant.apache.org/ivy/m2comparison.html
为什么要避免使用 Maven?以我的经验,Maven 是 Java 开发中为数不多的令人愉快的部分之一。
@Benson:这是一个有争议的问题。如果它是银弹,那么每个人都会使用它。
A
Ascalonian

仅列出更多差异:

Ant 没有正式的约定。您必须准确地告诉 Ant 在哪里可以找到源代码、在哪里放置输出等等。

蚂蚁是程序性的。你必须准确地告诉 Ant 该怎么做;告诉它编译,复制,然后压缩等。

Ant 没有生命周期。

Maven 使用约定。只要您遵循这些约定,它就会自动知道您的源代码在哪里。你不需要告诉 Maven 它在哪里。

Maven 是声明性的;您所要做的就是创建一个 pom.xml 文件并将您的源代码放在默认目录中。 Maven 将负责其余的工作。

Maven 有一个生命周期。您只需调用 mvn install 并执行一系列序列步骤。

Maven 具有关于常见项目任务的智能。要运行测试,只需执行 mvn test,只要文件位于默认位置即可。在 Ant 中,您首先需要 JUnit JAR 文件,然后创建一个包含 JUnit JAR 的类路径,然后告诉 Ant 它应该在哪里寻找测试源代码,编写一个编译测试源的目标,然后最后执行单元测试与 JUnit。

更新:

这来自 Maven: The Definitive Guide。对不起,我完全忘了引用它。


那更新是双关语吗?
@vakio - 我猜你的意思是因为我使用“站点”而不是“引用”?这对我来说完全是一个糟糕的拼写,我修复了它
C
Community

Maven or Ant? 是一个与此问题非常相似的问题,它应该可以帮助您回答问题。

What is Maven? 在官方网站上。

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


Maven 将在项目开始时为您节省时间,但随着时间的推移,如果您有其他项目不是非常简单的项目,Maven 脚本将变得比 Ant 等价物复杂得多。例如,查看 Maven Assembly 插件。
我认为以 Maven 格式(在其中以 xml 格式布置程序集模型)比在 Ant 中执行所有手动步骤更容易完成 Assembly 插件所做的事情,但是 YMMV
嗨,马特,组装插件的学习曲线比 Ant tar 或 zip 任务的学习曲线要陡峭得多。描述符格式大约有 150 行长,包含一大堆非直观的配置选项。最重要的是,它不起作用!在我放弃组装插件的那一刻,对 unpack 的过滤不起作用,文件模式选项也不起作用,它无法修复crlf。不确定“Ant 中的所有手动步骤”是什么意思。我花了大约 5 分钟让 Ant 完成我无法让程序集插件在几个小时内完成的事情。
第一个链接现在已经死了:/
J
James Kingsbery

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

Maven 依赖于项目目录布局的约定以实现其“声明性”。例如,它对放置主代码的位置、放置 web.xml 的位置、单元测试的位置等有一个约定,但也可以在需要时更改它们。

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

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

此外,maven 的原型使项目的启动速度非常快。例如,有一个 Wicket 原型,它提供了一个 maven 命令,您可以运行该命令来获得一个完整的、可立即运行的 hello world 类型的项目。

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


a
alex

我可以带一个从未见过 Ant 的人 - 它的 build.xml 写得相当好 - 他们可以理解发生了什么。我可以让同一个人向他们展示一个 Maven POM,他们不会知道发生了什么。

在一个庞大的工程组织中,人们写到 Ant 文件变得庞大且难以管理。我已经编写了这些类型并清理了 Ant 脚本。它真的是提前了解您需要做的事情,并设计一组可以在 3 年以上的时间内响应变化和扩展的模板。

除非你有一个简单的项目,否则学习 Maven 约定和 Maven 完成工作的方式是相当多的工作。

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

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


G
Gad

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


我不同意。我同意将 maven 用于简单项目是件好事,但我认为随着复杂性的增加,使用 maven 的好处会增加几个数量级。
我也不同意,当你有一个包含许多相互关联的模块的更复杂的系统时,Maven 真的开始运作良好。如果您需要编写功能测试、运行报告并将工件部署到存储库管理器,为什么要自己使用 Ant 来完成所有这些工作?
Maven 对于一个简单的项目来说很好,但我有一段时间做噩梦,试图在一个更复杂的项目中做一些应该简单的事情。例如,创建可分发包、混淆代码、创建 webstart 包、配置配置文件。 @Benson,随着您的项目变得越来越复杂,Maven 变成了一个球和链子。 Ant 的强大功能和灵活性将为您带来比 Maven 更大的生产力优势。 @tobrien,Ant 适用于多模块项目、编写功能测试等。在 Maven 中配置非默认报告插件通常比 Ant 等价物更冗长。
我刚刚开始将 maven 添加到现有项目中,我发现事情并没有按预期工作。该网站是用 php 构建的,并使用脚本进行部署。这些东西在 Maven 中不能顺利工作,你必须做一些非常奇怪的事情才能让它工作。
m
markt

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


+1,在了解了保持中央 Maven 存储库正常运行所需的条件后,我不得不插话并建议每个使用 Maven 和 Ivy 之类的东西的人都应该考虑安装存储库管理器。哪个没关系,但我偏爱 Nexus nexus.sonatype.org