Ant 与 Maven 的区别

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

186056 次浏览

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

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

Ant 主要是一个构建工具。

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

如果你想避开 Maven,Ant + 艾薇是一个很好的组合。

再列出一些不同之处:

  • Ant 没有正式的约定。您必须准确地告诉 Ant 在哪里找到源代码,在哪里放置输出,等等。
  • Ant 是过程性的,你必须准确地告诉 Ant 要做什么; 告诉它编译、复制、然后压缩,等等。
  • Ant 没有生命周期。
  • Maven 使用约定。只要遵循这些约定,它就会自动知道源代码的位置。你不需要告诉玛文它在哪。
  • Maven 是声明性的; 您所需要做的就是创建 pom.xml 文件,并将源代码放在默认目录中。剩下的交给玛文。
  • Maven 有一个生命周期,您只需调用 Mvn 安装并执行一系列的顺序步骤。
  • Maven 对常见的项目任务很有研究。要运行测试,只要文件位于默认位置,就执行 Mvn 测试。在 Ant 中,首先必须使用 JUnit JAR 文件 is,然后创建一个包含 JUnit JAR 的类路径,然后告诉 Ant 应该在哪里查找测试源代码,编写一个目标来编译测试源代码,最后用 JUnit 执行单元测试。

更新:

这是来自 美芬: 权威指南。对不起,我完全忘了引用它。

Maven 既可以作为依赖关系管理工具(它可以用于从中央存储库或您设置的存储库检索 jar) ,也可以作为声明性构建工具。“声明性”构建工具与更传统的构建工具(如 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

美芬: 权威指南中,我在引言部分的标题是 “蚂蚁与 Maven 的区别”中写到了 Maven 和 Ant 之间的区别。这里有一个结合了前言中的信息和一些附加注释的答案。

一个简单的比较

我给你们看这个只是为了说明这个想法,在最基本的层面上,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 包含声明: “ This is a JAR project”和“ The source code is in src/main/java”。Ant 构建文件包含明确的指令: “ This is project”、“ The source is in src/main/java”、“ Run javac against This directory”、“ Put The result in target/classses”、“ Create a JAR from The...”等等。在 Ant 必须明确说明流程的地方,Maven 有一些“内置”的东西,它只知道源代码在哪里,以及应该如何处理它。

高级别比较

在这个例子中,Ant 和 Maven 之间的区别是什么。

  • 没有像通用项目目录结构那样的正式约定,你必须准确地告诉 Ant 在哪里可以找到源代码,在哪里可以放置输出。随着时间的推移,非正式的约定出现了,但它们还没有被编入产品。
  • 是程序性的,您必须确切地告诉 Ant 要做什么和什么时候做。你必须告诉它编译,然后复制,然后压缩。
  • 没有生命周期,你必须定义目标和目标依赖关系。您必须手动将一系列任务附加到每个目标。

玛文..。

  • 它已经知道你的源代码在哪里,因为你遵循了约定。它将字节码放在 target/class 中,并在 target 中生成一个 JAR 文件。
  • 是陈述性的。您所需要做的就是创建 pom.xml 文件,并将源代码放在缺省目录中。剩下的就交给玛文了。
  • 有一个生命周期,您在执行 mvn install时调用了它。这个命令告诉 Maven 执行一系列的顺序步骤,直到达到生命周期。作为这个生命周期旅程的一个副作用,Maven 执行了许多默认的插件目标,这些目标包括编译和创建 JAR。

艾薇呢?

没错,所以像 Steve Loughran 这样的人会读到这个比较,然后判犯规。他将谈到答案是如何完全忽略了常青藤(Ivy)这一概念,以及 Ant 可以在最近的 Ant 版本中重用构建逻辑这一事实。这倒是真的。如果你有一群使用 Ant + antlibs + Ivy 的聪明人,你最终会得到一个设计良好的可以工作的版本。尽管如此,我还是非常相信 Maven 是有意义的,我很乐意与一个拥有非常出色的构建工程师的项目团队一起使用 Ant + Ivy。也就是说,我确实认为你最终会错过一些有价值的插件,比如 Jetty 插件,你最终会做一大堆你不需要花时间去做的工作。

比 Maven 和 Ant 更重要

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

我可以选择一个从未见过 Ant 的人——它的 build.xml写得相当不错——他们能够理解正在发生的事情。我可以采取同样的人,并向他们展示一个 MavenPOM,他们将不会有任何想法是怎么回事。

在一个庞大的工程组织中,人们写到 Ant 文件变得越来越大,难以管理。我已经编写了这些类型的 还有干净 Ant 脚本。它真正的理解前面你需要做什么,并设计一套模板,可以响应变化和规模超过3年的时间。

除非您有一个简单的项目,否则学习 Maven 约定和 Maven 完成任务的方法是一项相当繁重的工作。

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

构建系统最重要的方面是依赖关系管理和表达构建配方的灵活性。做得好的时候一定要有点直觉。

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 会减少。我发现事实恰恰相反。Xml 比 build.xml 长3倍,而且没有偏离约定。事实上,我的 Maven 示例没有显示配置插件所需的额外54行代码。Xml 用于一个简单的项目。当您开始添加额外的需求时,XML 确实开始显著增长,这对于许多项目来说并不奇怪。

但你得告诉 Ant 该怎么做

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

这是真的,如果我不需要显式地编写这些 Ant 目标,它将节省我的时间。但还有多少时间?我现在使用的通用构建文件是我5年前编写的,从那时起只进行了一些细微的改进。在我用 Maven 做了两年的实验之后,我把旧的 Ant 构建文件从柜子里拿出来,掸去上面的灰尘,让它重新开始工作。对我来说,在5年的时间里,明确告诉 Ant 要做什么的成本加起来不到一周。

复杂性

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

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

  • 阅读文档: 有关 Maven 的文档要多得多,因为您需要学习的内容要多得多。
  • 教育团队成员: 他们发现询问知情者比自己寻找答案更容易。
  • 构建疑难解答: Maven 不如 Ant 可靠,尤其是非核心插件。此外,Maven 构建是不可重复的。如果您依赖于插件的 SNAPSHOT 版本(这种情况很有可能发生) ,那么您的构建可能会中断,而不需要更改任何内容。
  • 编写 Maven 插件: 插件通常是为特定的任务编写的,例如创建 webstart 包,这使得它们很难重用于其他任务或者组合它们来实现目标。因此,您可能必须自己编写一个来解决现有插件集中的空白。

相比之下:

  • Ant 文档简洁、全面并且集中在一个地方。
  • 蚂蚁很简单。试图学习 Ant 的新开发人员只需要理解一些简单的概念(目标、任务、依赖项、属性) ,就能够弄清楚他们需要知道的其余部分。
  • Ant 是可靠的。在过去的几年里,由于它已经可以工作了,所以还没有太多的 Ant 版本。
  • Ant 构建是可重复的,因为它们通常是在没有任何外部依赖的情况下创建的,比如在线存储库、实验性的第三方插件等等。
  • 蚂蚁是综合性的。因为它是一个工具箱,所以您可以组合这些工具来执行几乎任何您想要的任务。如果您需要编写自己的自定义任务,这非常简单。

熟悉感

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

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