ant和Maven的区别
有人能告诉我ant和Maven之间的区别吗? 我从来没有用过。 我知道他们习惯于自动化Java项目的构build,但是我不知道从哪里开始。
在“ Maven:权威指南”中 ,我介绍了Maven和Ant之间在引言中的区别,标题是“Ant和Maven之间的差异” 。 这里有一个答案,是介绍中的信息和一些额外的注释的组合。
一个简单的比较
我只是向你展示这个想法,以说明在最基本的层面上,Maven有内置的约定。 这里有一个简单的Ant构build文件:
<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文件中。 尽pipe最近的一些发展有助于减lessAnt,但开发人员使用Ant的经验是编写用XML编写的程序语言。
将之前的Ant示例与Maven示例进行对比。 在Maven中,要从某个Java源代码创build一个JAR文件,只需要创build一个简单的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将处理资源,编译源代码,执行unit testing,创buildJAR,并将JAR安装在本地存储库中,以便在其他项目中重用。 如果不进行修改,您可以运行mvn站点,然后在target / site中find一个index.html文件,其中包含指向JavaDoc的链接以及一些关于您的源代码的报告。
无可否认,这是最简单的示例项目。 只包含源代码并生成JAR的项目。 遵循Maven约定的项目,不需要任何依赖或定制。 如果我们想开始自定义这个行为,我们的pom.xml将会增长,而在最大的项目中,你可以看到非常复杂的Maven POM的集合,这些集合包含大量的插件自定义和依赖声明。 但是,即使项目的POM文件变得更加实质化,它们也会使用Ant来从类似大小的项目的构build文件中获取完全不同的信息。 Maven POM包含声明:“这是一个JAR项目”,“源代码在src / main / java”。 Ant构build文件包含显式指令:“这是项目”,“源在src/main/java
”,“对此目录运行javac
”,“将结果放入target/classses
”,“从中创buildJAR”。 …“等等。在Ant需要明确过程的地方,Maven有一些”内置“的东西,只知道源代码在哪里以及如何处理。
高级比较
Ant和Maven在这个例子中的区别? ant…
- 没有像普通项目目录结构那样的正式约定,你必须告诉Ant究竟在哪里find源代码以及在哪里放置输出。 随着时间的推移,非正式的惯例已经出现,但是它们还没有被编入产品中。
- 是程序性的,你必须告诉Ant究竟该做什么,什么时候去做。 你必须告诉它编译,然后复制,然后压缩。
- 没有生命周期,你必须定义目标和目标依赖。 您必须手动将一系列任务附加到每个目标。
凡Maven …
- 有惯例,它已经知道你的源代码是在哪里,因为你遵循了惯例。 它将字节码放在目标/类中,并在目标中生成一个JAR文件。
- 是声明性的。 你所要做的只是创build一个pom.xml文件,并将你的源文件放在默认目录中。 Maven照顾了其余的人。
- 有一个生命周期,当你执行
mvn install
时候你调用了这个生命周期。 这个命令告诉Maven执行一系列的顺序步骤,直到达到生命周期。 作为整个生命周期的一个副作用,Maven执行了一些默认的插件目标,比如编译和创build一个JAR。
常春藤呢?
对,所以像史蒂夫·拉夫兰(Steve Loughran)这样的人会阅读这个比较,并称之为犯规。 他将会谈论这个答案完全忽略了一个叫Ivy的东西,以及Ant可以在更新版本的Ant中重用构build逻辑的事实。 这是真的。 如果你有一群使用Ant + antlibs + Ivy的聪明人,那么你将会得到一个devise良好的构build。 尽pipe我非常确信Maven是有道理的,但我很乐意使用Ant + Ivy和一个非常敏锐的构build工程师的项目团队。 话虽如此,我认为你最终会错过一些有价值的插件,比如Jetty插件,最终你会做很多你不需要做的工作。
比Maven和Ant更重要
- 是否使用Repository Manager来跟踪软件工件? 我build议下载Nexus 。 您可以使用Nexus代理远程存储库,并为您的团队提供一个部署内部工件的位置。
- 您有适当的软件组件模块化。 一个庞大的整体组件很less会随着时间而缩放。 随着您的项目的发展,您将需要有模块和子模块的概念。 Maven非常适合这种方法。
- 你为你的构build采用一些约定。 即使使用Ant,也应该努力采取与其他项目一致的某种forms的约定。 当一个项目使用Maven时,这意味着任何熟悉Maven的人都可以拿起构build并开始运行,而不必为了弄清楚如何获得编译而进行configuration。
Maven是一个框架,Ant是一个工具箱
Maven是预制的公路车,而Ant则是一组汽车零件。 用ant你必须build立自己的车,但至less如果你需要做任何越野驾驶,你可以build立正确的types的汽车。
换句话说,Maven是一个框架,而Ant是一个工具箱。 如果你满足于在框架的范围内工作,那么Maven会做的很好。 对我来说问题是我一直在碰撞框架的边界,它不会让我出去。
XML冗长度
tobrien是一个对Maven非常了解的人,我认为他提供了一个很好的,两个产品的诚实比较。 他比较了一个简单的Maven pom.xml和一个简单的Ant构build文件,他提到了Maven项目如何变得更加复杂。 我认为值得关注一下你在一个简单的实际项目中更容易看到的几个文件的比较。 下面的文件表示多模块构build中的单个模块。
首先,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有内置的约定,但这并不一定意味着你最终会写更less的XML。 我发现情况正好相反。 pom.xml比build.xml长3倍,并且没有偏离约定。 事实上,我的Maven示例没有显示额外的54行configuration插件。 该pom.xml是一个简单的项目。 当你开始添加额外的需求时,XML确实开始显着增长,这对于许多项目来说并不是不寻常的。
但是你必须告诉Ant该怎么做
我上面的Ant示例当然不完整。 我们仍然必须定义用于清理,编译,testing等的目标。这些目标是在多模块项目中的所有模块导入的通用构build文件中定义的。 这引出了我关于如何将所有这些东西都明确地写在Ant中的观点,而在Maven中则是声明式的。
它的确如此,如果我不必明确地写出这些Ant目标,这将节省我的时间。 但是多less时间? 我现在使用的通用构build文件是5年前我写的一个文件,从那以后只有很less的改进。 在对Maven进行了2年的实验之后,我将旧的Ant构build文件从壁橱中取出,掸掉它,然后重新开始工作。 对我来说,不得不明确地告诉Ant要做什么的成本在5年内增加了不到一周的时间。
复杂
我想提到的下一个主要区别是复杂性和真实世界的影响。 Maven的目的是减less开发人员的工作量,负责创build和pipe理构build过程。 为了做到这一点,它必须是复杂的。 不幸的是,复杂性往往会否定他们的预期目标。
与Ant相比,Maven项目的构build人员会花费更多的时间:
- 阅读文档:有更多关于Maven的文档,因为你需要学习的东西太多了。
- 教育团队成员:他们发现问一个知道而不是试图自己找答案的人更容易。
- 对构build进行故障诊断:Maven比Ant更不可靠,尤其是非内核插件。 另外,Maven构build不可重复。 如果你依赖一个插件的SNAPSHOT版本,很可能你的版本会被破坏,而你没有改变任何东西。
- 编写Maven插件:插件通常是针对特定的任务编写的,例如创build一个webstart包,这使得重用它们用于其他任务或将它们结合以实现目标更加困难。 所以你可能必须写一个你自己的解决scheme来弥补现有的插件集。
相反:
- ant文档是简洁,全面的,在一个地方。
- ant很简单。 试图学习Ant的新开发人员只需要理解一些简单的概念(目标,任务,依赖关系,属性)就可以弄清楚他们需要知道的其余部分。
- ant是可靠的。 过去几年中Ant的发布并不多,因为它已经可以工作了。
- Ant构build是可重复的,因为它们通常是在没有任何外部依赖的情况下创build的,如在线存储库,实验性第三方插件等。
- ant是全面的。 因为它是一个工具箱,所以你可以组合这些工具来执行你想要的任何任务。 如果您需要编写自己的自定义任务,那么执行起来非常简单。
熟悉
另一个区别是熟悉。 新开发人员总是需要时间来加快速度。 对现有产品的熟悉有助于Maven的支持者正确地宣称这是Maven的一个好处。 当然,Ant的灵活性意味着你可以创build你喜欢的任何约定。 所以我使用的约定是把我的源文件放在目录名src / main / java中。 我编译的类进入一个名为target / classes的目录。 听起来很熟悉,不是。
我喜欢Maven使用的目录结构。 我认为这是有道理的。 也是他们的构build生命周期。 所以我在我的Ant构build中使用相同的约定。 不仅仅是因为它是有道理的,而且因为以前使用Maven的人都会熟悉它。
ant主要是一个构build工具。
Maven是一个项目和依赖关系pipe理工具(当然也可以build立你的项目)。
如果你想避开Maven,Ant + Ivy是一个相当不错的组合。
Maven还是Ant? 是一个非常类似的问题,这应该可以帮助你回答你的问题。
什么是Maven? 在官方网站上。
编辑:对于一个新的/新build项目,我build议使用Maven:“约定优于configuration”将为您节省大量时间编写和设置构build和部署脚本。 当你使用ant时,构build脚本的长度和复杂度会随着时间而增长。 对于现有的项目,可能很难将他们的configuration/布局压缩到Maven系统中。
只是列出一些更多的差异:
- ant没有正式的约定。 你必须告诉Ant究竟在哪里find源代码,在哪里放置输出等。
- ant是程序性的。 你必须告诉Ant究竟该做什么; 告诉它编译,复制,然后压缩等
- Ant没有生命周期。
- Maven使用约定。 它知道你的源代码是自动的,只要你遵循这些约定。 你不需要告诉Maven它在哪里。
- Maven是声明式的; 你所要做的就是创build一个pom.xml文件,并将你的源文件放在默认的目录下。 Maven会照顾其余的。
- Maven有一个生命周期。 您只需调用mvn install,然后执行一系列序列步骤。
- Maven拥有关于常见项目任务的情报。 要运行testing,只要执行mvn test ,只要文件在默认位置。 在Ant中,你首先要创build一个JUnit JAR文件,然后创build一个包含JUnit JAR的类path,然后告诉Ant它应该在哪里查找testing源代码,编写一个编译testing源的目标,然后执行unit testing与JUnit。
更新:
这来自Maven:权威指南 。 对不起,我完全忘了引用它。
Maven既是一个依赖pipe理工具,也可以用来从一个中央仓库或者从你设置的仓库中检索jar子,还可以作为一个声明式的构build工具。 “声明式”构build工具与更传统的构build工具(如ant或make)之间的区别在于,您需要configuration需要完成的任务,而不是如何完成。 例如,你可以在maven脚本中说一个项目应该被打包成一个WAR文件,maven知道如何处理这个文件。
Maven依靠关于如何布置项目目录以实现其“声明性”的约定。 例如,它有一个约定,你可以在哪里放置你的主代码,在哪里放置你的web.xml,你的unit testing等等,还可以根据你的需要改变它们。
你还应该记住,在maven中有一个运行ant命令的插件:
http://maven.apache.org/plugins/maven-ant-plugin/
而且,maven的原型使得一个项目的入门非常快。 例如,有一个Wicket原型,它提供了一个maven命令来运行,以获得一个完整的,随时可以运行的hello worldtypes的项目。
我可以找一个从来没有见过Ant的人 – 它的build.xml
写得相当好 – 他们可以理解到底发生了什么。 我可以带同一个人,向他们展示一个Maven POM,他们不知道发生了什么。
在一个庞大的工程组织中,人们写的关于Ant文件变得庞大而难以pipe理。 我写了这些types和清洁的Ant脚本。 我们非常了解您需要做什么,并devise一套模板,可以应对3年以上的变化和规模。
除非你有一个简单的项目,否则学习Maven的约定和Maven的方式来完成工作是相当的工作。
在一天结束的时候,您不能考虑使用Ant或Maven进行项目启动:这是真正的总体拥有成本。 组织在几年内维护和扩展构build系统需要的是必须考虑的主要因素之一。
构build系统最重要的方面是依赖性pipe理和expression构build配方的灵活性。 做得好的时候一定有点直觉。
我会说这取决于你的项目的规模… Personnally,我会使用Maven简单的项目,需要直接编译,打包和部署。 只要你需要做一些更复杂的事情(很多依赖,创build映射文件…),我会切换到Ant …
Maven也有一个常用的开源项目的大型仓库。 在构build过程中,Maven可以为你下载这些依赖关系(以及你的依赖关系:)),使得构build项目的这一部分更容易pipe理。