`
zljpp
  • 浏览: 255345 次
社区版块
存档分类
最新评论

Java Build工具Ant与Maven之比较

    博客分类:
  • java
阅读更多

没有一件东西能满足你的全部想法除非你自己创造一个出来。同样对于Build工具来说,也许最好的就是你自己写的。每个项目的Build过程都是独特的,而且通常你的项目要用多种方式构建。对Build工具的作者来说,设想每个构建的需求以迎合它基本是不现实的。工具最好就是提供一个灵活的库和可以重用的任务来被我们按需调用,但是这样也远远不够,成品的工具从来不会100%满足你的需求。你会浪费大量的时间让那些任务能按你的想法去工作,但是最后可能不得不自己写一个插件了事。写自己的定制化构建工具是快且容易的,比你担忧的维护量要少很多。构建就是要适合你的项目,而不是别的什么东西,这有什么可担心的。

 

如果你不想自己写构建工具,你可以用Rake。Rake是目前最好的基于Ruby语言编写的Java项目构建工具。Rake提供了一堆标准的方法来完成通常的构建任务,任何其他的任务都可以通过Ruby快速实现。Rake是用一个真正的程序语言(Ruby)来写构建脚本,这是它优于其它工具的地方。当然,Rake还有许多其它的优点,但都没有这个重要。

因此,你应该自己写构建工具,如果不想自己写,那就用Rake吧。如果你不想转向Rake,你也应该劝说他们转向正确的工具。假如技术上的决定被其它东西(办公室政?治)左右,假如不允许你这样做,那就离开这个项目,没什么好说的。

如果你没有勇气退出,那么使用Ant吧。对Java项目来说,Ant是第二好的构建工具。虽然不如Rake,Ant仍然可以说是最牛?B的构建工具。Ant成熟且稳定,快速且工具集丰富。Ant能让你把复杂的项目构建过程通过合身的脚本表达出来,虽然不全都是那么简单。

总而言之,写自己的构建工具,不行就转向Rake,不让转就力争或者辞职到其它让你用Rake的地方。如果全都不行,就用Ant吧,直到哪天有个公司使用Rake就跳过去。

就这些,这就是我能建议你们的唯一选择。因为,你们绝对不要、永远不要,在任何情况下试图使用Maven。

Maven的构建本身就是一个无穷无尽的绝望的怪圈,它一点一点地把你拖进万劫不复的Maven地狱。起初你就用了10分钟就搭好了Maven环境,你因此手舞足蹈。可是随着项目的进展,你的配置要增加,原来的pom.xml肯定是不够用了。为了让项目按你想要的方向上发展,你要一点点地增加配置。用不了多久,你就会第一次鬼打墙般地遇到问题。(用“鬼打墙”这个词,我的意思是“突然搞得人很头疼”。之所以说“第一次”,因为将来你还会不断地鬼打墙)。终于有一天,你会为了解决一个燃眉之急而临时凑合地改了改这个已经乱的不成样子的pom.xml。你可能还对Maven满意了好一阵子...直到又有一个问题露出了恶心的小头(这让我想起女孩青春期挤脸上粉刺的情景。当她挤掉脸上出现的第一个粉刺豆豆,她会好有成就感。可是当豆豆越来越多,挤也挤不干净的时候,她就不再对少女时期洁白无瑕的脸庞抱有幻想了——译者注)。这让我联想到希腊神话里的悲剧,你就是被打入地狱的灵魂,带着永世的诅咒——你的基于Maven的构建过程。

严肃地说,Maven就是坏主意的糟透了的实现。我相信总是有人认为Maven即使不性感,起码也够清晰智能,可是,现实上Maven的实现毫无这些迹像。实际上,Maven是彻头彻尾地糟透了,已经成为了一个著名的反例——告诉人们如何不要去构建软件。当构建正在以Maven相反的方式工作,你知道这是多么的可怕。

例如从Maven's Surefire 插件输出的测试结果。(Surefire插件用来在Maven构建生命周期的测试阶段执行一个应用的单元测试。它会产生两种不同形式的测试结果报告:纯文本;.xml文件。默认情况下,这些文件生成在工程${pom文件所在的目录}/target/surefire-reports目录下。——译者注)。只要测试通过一切万事大吉,但是如果出了错误,Surefire的测试报告就是一个调试的梦魇。只有失败的测试类的名称被记录下来。你必须手动地查看target/surefire-reports/目录下的日志文件,这些日志文件是按每个测试类组织的。如果多个测试类都失败了,你就必须分别地检查多个日志文件。看上去是个小事情,累积起来会让人一肚子怨气,从而生产效率下降。

Maven主张的约定优于配置,其实是个谎言。Maven支持的唯一约定是:编译,运行单元测试,生成jar包。做其它任何事情就开始要配置了:生成war包?要配置;从命令行运行程序?要配置;运行验收测试(把所有系统理论上目前支持的场景都列出来,然后按功能分类测试,如果测试成功,就在此场景中标明“成功”,否则,就标明“失败”。——译者注)或功能测试或性能测试,还是要配置它,但是涉及到不能运行你的单元测试,或者在常规的单元测试阶段不能运行。想要生成项目的代码覆盖率度量?你还要配置,但是你的测试要运行2次(或者可以只运行一次,只是不能在常规的单元测试阶段);尽管是做全方位的测试,它还是经常会报告了0%的代码覆盖率。

谈到配置,Maven的配置语法是Sendmail(在Unix系统的用户中,Sendmail是应用最广的电子邮件服务器。Sendmail作为一种免费的邮件服务器软件,已被广泛的应用于各种服务器中,它在稳定性、可移植性、健壮性等方面很出色。)以来最让人反胃的了——交替正常格式的XML。因此,Maven配置累赘,拗口,难写。在Ruby、Rake的XML或者Ant中1、2行就可以搞定的事情,在pom.xml里要6、7、8行才可以做到(还要假设Maven能做到才行)。

Maven的配置一点也不连贯。一会引用classpath的相对路径,一会用相对于磁盘的绝对路径,一会又用运行于JVM之上的Maven的系统属性。有些绝对路径能被移植是因为Maven知道怎么自动纠正错误,有些纠正不了。有时Maven智能地知道如果递归地构建项目,有时经常又不行。

而且,有些东西在pom中根本无法配置。比如:Maven仓库、服务器、授权凭据等是在settings.xml配置的。既然pom.xml要提交到项目的版本控制仓库,那么Maven把用户密码置于pom.xml文件之外是言之有据的。可是Maven的解决方法太恐怖了:所有的这类配置被放进了一个叫做settings.xml的文件里,而这个文件不在任何的项目目录里。你不能直接地在桌面电脑和笔记本、其它开发者或者你的项目构建服务器之间共享任何这类配置。但是,它却自动地在你工作的每个单独的Maven项目间共享,潜在地在同一台计算机上的不同用户之间的每个Maven项目间共享。当一个新的开发者加入到项目中,就必须手动合并必要的配置信息到原有的settings.xml中。当一个新的代理被加到构建服务器里,还是要手动合并必要的配置信息到原有的settings.xml中。同上,当你迁移到新的机器。任何这些配置需要更新,必须手动地在每个单独的机器上更新。这也是一个在Maven到来之前就已经解决的问题:属性文件。项目组把通用的属性文件提交到版本控制,然后每个开发者在本地的属性文件中覆盖这些信息,本地的属性文件中不提交到版本控制。

所有这些东西在Maven里——那些约定,配置,过程——被以所谓的Maven方式管理。不幸的是,所谓的Maven方式没有文档说明。为了抓住那一定点儿稍纵即逝的信息,往往要在Maven文档里拉网式地搜索,Google,或者买Maven开发者们写的书。(有点类似众里寻她千百度,蓦然回首,不知春归处——译者注)。还有的另外办法来找到所谓的Maven方式就是鬼打墙了。(走着走着被自己要找的东西绊倒了。作者的意思就是这——所谓的Maven方式——就像看不见的边界,试图找到它的办法可能就是不经意地撞到它——译者注)。Maven的构建不是为了灵活,不支持每种可能的构建过程。Maven是为了Apache项目而构建的,假定了每个项目的构建过程都像Apache项目自身一样。这对自愿奉献自己时间的开源库的开发者来说是个好消息,对于这些人,“发布”意味着“上传一个新的zip文件到你的站点为了便于其他人手动发现,下载然后添加到他们自己的项目中。” 其实这是溜须拍马的做法。Rake和Ant可以适应每种构建过程,Maven不能;Maven也许,实际上很可能,它恰恰不能支持你想要的那种构建软件的方式。

还有就是Maven的依赖管理是彻头彻尾地不可挽回的破坏。事实上,我收回我的话;Maven的下载ibiblio(Maven会从ibiblio.org中的公用仓库中同步构件,这个公用仓库下载缓慢、 不稳定,并且不包含一些构件的最新版本,而且不能上传团队私有的构件。——译者注)到用户的home目录,然后一古脑地把所有东西像垃圾一样倒在classpath下。这种傻到让人难以置信的依赖管理策略是极其错误的,从来不应与“依赖管理”混淆。我近来工作的一个Maven工程,它产生出一个51MB的.war文件;当我把它转到Ant下手动配置依赖管理,这个.war文件减小到了17MB。靠,51-17=34=17x2,居然原来三分之二的东西都是Maven给我们制造的无用的废物。

不相干的依赖包不仅仅吃掉硬盘空间,而且会吃掉宝贵的内存。Maven完全就是多吃多占内存的大蠢猪。相对简单的项目,只带有一个父pom和一些子模块,就要求一大堆的JVM内存——通过改变JAVA_OPTS配置来得到,而这些精巧的JAVA_OPTS配置通常你仅仅在产品服务器上才用到。如果整合Maven构建工具到你的IDE,事情可能更糟。它把JVM的最大堆尺寸设成好几百兆,把最大的PermGen尺寸设成几百兆,并启用permgen sweeping,这样类自己会被垃圾回收。(PermGen——Permanent Generation space,是指内存的永久保存区域。这一部分用于存放Class和Meta的信息,Class在被Load的时候被放入PermGen区域,它和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen进行清理,所以如果你的APP会Load很多Class的话,就可能出现PermGen错误。——译者注)。所有这一切仅仅是构建你的项目,或者在IDE里与Maven一起工作。

一个可笑的故事:在上面那个项目里,我曾经经历了一个10分钟的“mvn clean”构建命令,因为Maven愚蠢地想在“rm -rf ./target/”之前做点事情 (参考类似的例子: http://gist.github.com/267553)。实际这个故事一点不可笑;相信我,你不想要一个工具——它在清空你的构建输出目录之前自动下载所有未解析的依赖包。你不想要一个工具——它自动下载所有未解析的依赖包。隔一段时间就下载所有未解析的依赖包让你的构建过程变得不确定。好,我是不确定主义者:这在学校里好玩,不是在工作中。

所有那些不必要的,不想要的网络来回占有了大量时间。每一次构建你都要为Maven的破坏性的包依赖管理付出性能的代价。10分钟的clean构建是恐怖的,但是每次构建都多几分钟就更糟了。我估算的每次构建的平均额外消耗时间大约是一分钟,这是基于一个事实:我把Maven项目迁移到Ant上,平均构建时间缩短了2.5分钟到1.5分钟;类似地把Ant项目迁移到Maven上,平均构建时间增长了2~3分钟。

你无法控制,也看不清哪些包被哪些包指定。构建可能中断因为不同的Maven版本在不同的时间会下载不同的包。你的本地构建有一天也会中断,当你的依赖包的依赖包偶然地发布了新的,不向后兼容的改变而忘记了敲上版本号;那些失败是无辜的。更容易发生的情况是你的项目A依赖了某个特定版本的其它项目B,而这个项目B反过来依赖某个最后版本的另外的项目C,这时你还蒙在鼓里,即使下游包提供者敲上了正确的版本号。每次发布依赖包的依赖包都可能造成新的错误,从而会浪费你几个小时去追踪为何构建失败。

但是Maven比这甚至还要糟的是:Maven不仅仅解决你的项目的包依赖,它还自动解决自己带的插件的包依赖。于是现在你不仅仅要担心不同的Maven实例偶然会下载不兼容的东西(或者同一个Maven在不同的时间下载不同的东西),你还要担心你的构建工具在不同计算机的不同时间上的行为不一致。

Maven的残缺不堪的包依赖管理同时带来了一个安全的隐患,既然Maven目前不可能确定包最初来自哪里,被篡改与否。当上传包到代码仓库中,包会被自动数字签名,当Maven下载包时会自动验证签名,可是Maven无疑地信任代码仓库中的签名。当前Maven的包安全是由Maven开发者控制的,他们有对ibiblio权威信息库写的权限。但是无法知道你下载的包的所有依赖包的代码仓库是不是中毒了,没有办法知道你的本地仓库缓存是不是中毒了,也无法知道你本地仓库缓存中里的包来自哪里和谁上传了它们。

综上问题并不是粗心的程序员造成的,也无法通过仓库管理员锁定每个Maven需要的包来解决。如果Maven假设人从来不犯错误,那它就是一个破烂货(Maven is broken and wrong)如果Maven要使用者明确指定每个依赖的版本,每个依赖的依赖,来减少下载不兼容的包的可能性,那它就是一个破烂货。如果Maven非得通过一个第三方工具来阻止它连接到网络并自动下载那些乱七八糟的狗?屎,那它就是一个破烂货。如果Maven无视每次构建都要连接到网络,为任何更新都检查每个依赖项,然后自动下载它们,从而让构建过程变得缓慢不堪,那它就是一个破烂货。如果Maven在我的办公室和家里的笔记本电脑上表现的不一致,那它就是一个破烂货。如果Maven连删除一个目录都需要互联网,那它就是一个破烂货。Maven就是一个破烂货。

分享到:
评论
1 楼 yszy 2012-06-01  
一直以为只有我反感Maven,没想到知音还挺多。开源的工具太多了,多到学不完,一直无法理解为什么要把简单的事情变得这么复杂。Maven看着貌似很牛逼,其实带来的是无穷无尽的痛苦,都是浮云!一切都是浮云,java、javac、jar......简单命令搞定一切,零学习成本。简单就是最好的!

相关推荐

    apache-maven-3.8.5

    当时有一些项目(有各自Ant build文件),仅有细微的差别,而JAR文件都由CVS来维护。于是希望有一种标准化的方式构建项目,一个清晰的方式定义项目的组成,一个容易的方式发布项目的信息,以及一种简单的方式在多个...

    build-tool-overkill:可以使用 Ant、Maven 和 Gradle 构建的示例 Java 项目(用于比较目的)

    构建工具矫枉过正可以使用 Ant、Maven 和 Gradle 构建的示例 Java 项目(用于比较目的)。使用蚂蚁要编译和测试项目,请运行ant test 。 要生成覆盖率报告,请运行ant report 。 要将项目发布到本地目录,请运行ant ...

    selenium+java+Maven-TestNG+reportNG框架代码

    #框架介绍 selenium+java+Maven-TestNG+reportNG+XML • 使用Java作为项目编程语言 • 使用Maven作为项目类型,方便管理架包 • 使用TestNG作为项目运行... • 使用Ant作为Java的build打包工具,方便项目代码打包

    maven 3.8.8 解压安装版

    当时有一些项目(有各自Ant build文件),仅有细微的差别,而JAR文件都由CVS来维护。于是希望有一种标准化的方式构建项目,一个清晰的方式定义项目的组成,一个容易的方式发布项目的信息,以及一种简单的方式在多个...

    introduction-to-build-tools:格但斯克理工大学系列讲座的构建工具(Ant、Maven、Gradle)使用示例

    要求这个项目的系统需求非常小: Java SE SDK 1.7 或更高版本Apache Maven 3.0 或更高版本Apache Ant 1.9.0 或更高版本Apache Ivy 2.4.0 或更高版本Ant-Contib 任务 0.3 或更高版本参考补充阅读执照此存储库中的代码...

    Maven2之旅 构建项目 文档编制

    自从Java诞生以来,打包,测试,代码检测和发布Java工程就成为困扰Java程序员的枷锁,即使Ant出现,程序员深受困扰,而且Ant的 Xml格式的Build文件的学习阶梯又给程序员加重了一层负担.程序员头顶上的天空依然阴霾,只到有...

    Maven权威指南 很精典的学习教程,比ANT更好用

    比较Maven和Ant 1.8. 总结 2. 安装和运行Maven 2.1. 验证你的Java安装 2.2. 下载Maven 2.3. 安装Maven 2.3.1. 在Mac OSX上安装Maven 2.3.2. 在Microsoft Windows上安装Maven 2.3.3. 在Linux上安装Maven ...

    Maven2 的新特性.7z

    在Maven2中有了明确的生命周期概念,而且都提供与之对应的命令,使得项目构建更加清晰明了。主要的生命周期阶段: • validate,验证工程是否正确,所有需要的资源是否可用。 • compile,编译项目的源代码。 • ...

    maven入门到精通

    在 Java世界中我们很多的开发人员选择用 Ant来构建项目,一个 build.xml能够完成编译、测试、打包、部署等很多任务,但我们也碰到了很多的问题,如 jar文件管理混乱,各个项目结构和 build.xml相差很大等等。...

    maven-ant-tasks:Apache Maven ant任务的镜像

    maven-ant-tasks:Apache Maven ant任务的镜像

    Maven入门--概念与实例

    POM:POM(pom.xml)是Maven的核心文件,它是指示Maven如何工作的元数据文件,类似于Ant中的build.xml文件。POM文件位于每个工程的根目录中。 GroupId:groupId是一个工程的在全局中唯一的标识符,一般地,它就是...

    gradle 用户指南

    Java工程编译工具类似Ant,Maven

    maven-resolver-ant-tasks:Apache Maven Artifact Resolver Ant任务

    这样,您可以确保您不会浪费时间在Apache Maven范围之外的东西上。 假设您的问题不存在,请提交该问题的票证。 清楚地描述问题,包括在出现错误时重现的步骤。 确保填写您知道存在问题的最早版本。 在GitHub上...

    JavaBuilder:Java项目管理和构建工具,使用Java语言(适用于Java 6+)

    该工具与其他工具(例如Ant,Maven,Ivy,Gradle等)之间的主要区别在于,该构建工具使您可以直接在Java中工作。 由于您正在构建Java项目,因此可以安全地假定您已经知道Java。 另外,由于它正在运行编译的代码(而...

    Java-Build-System:高度定制的java构建系统

    描述这是一个基于 Apache Ant 的 java/web 项目的构建系统,我创建这个系统而不是使用 maven 的原因是让事情只专注于我关心的事情完全控制如何完成事情,而不仅仅是需要做什么。特征构建/打包/Junit 测试FindBugs ...

    Eclipse中使用ANT

    前言 ant是java开发者工具箱的重要一环,junit,xdoclet等都与它紧密关联,程序员可能习惯了IDE提供的自动构建,甚至部署的功能,从而忽略了ant本身,其实,主流的IDE通常是内置ant任务来完成这些工作的,熟悉ant内在...

    java8看不到源码-buildserver:Jenkins在centos上使用Vagrant和Ansible

    Java、Ant、Maven、Gradle、Jenkins、Sonar、Nexus、Artifactory,以 MariaDB 作为数据库。 它完全配置了开源书籍的示例项目(game-of-life)。 Jenkins 和 Sonar 的插件是从 roles/jenkins/vars/main.yml 和 roles/...

    Professional Java Tools for Extreme Programming (JAVA经典书籍英文版)_part2

    In the last few years, open source developers have created or significantly improved a host of Java XP tools, from XDoclet, Maven, AntHill, and Eclipse to Ant, JUnit, and Cactus. This practical, code...

    Professional Java Tools for Extreme Programming (JAVA经典书籍英文版)_part1

    In the last few years, open source developers have created or significantly improved a host of Java XP tools, from XDoclet, Maven, AntHill, and Eclipse to Ant, JUnit, and Cactus. This practical, code...

    Building and Testing with Gradle

    Discover how Gradle improves on the best ideas of Ant, Maven, and other build tools, with standards for developers who want them and lots of flexibility for those who prefer less structure.

Global site tag (gtag.js) - Google Analytics