许晓斌-- 四月 05, 2011
Maven面临的挑战
软件行业新旧交替的速度之快往往令人咂舌,不用多少时间,你就会发现曾经大红大紫的技术已经成为了昨日黄花,当然,Maven也不会例外。虽然目前它基本上是Java构建的事实标准,但我们也能看到新兴的工具在涌现,比如基于Goovy的Gradle,而去年Hibernate宣布从Maven迁移至Gradle这一事件更是吸引了不少眼球。在此之前,我也听到了不少对Maven的抱怨,包括XML的繁冗,不够灵活,学习曲线陡峭等等。那Gradle是否能够在继承 Maven优点的基础上,克服这些缺点呢?带着这个疑问,我开始阅读Gradle的文档并尝试着将一个基于Maven的项目转成用Gradle构建,本文所要讲述大概就是这样的一个体验。需要注意的是,本文完全是基于Maven的角度来看Gradle的,因此对于Ant用户来说,视角肯定会大有不同。
Gradle初体验
Gradle的安装非常方便,下载ZIP包,解压到本地目录,设置 GRADLE_HOME 环境变量并将 GRADLE_HOME/bin 加到 PATH 环境变量中,安装就完成了。用户可以运行gradle -v命令验证安装,这些初始的步骤和Maven没什么两样。Gradle目前的版本是1.0-milestone-1,根据其Wiki上的Roadmap,在1.0正式版发布之前,还至少会有3个里程碑版本,而1.0的发布日期最快也不会早于6月份。而正是这样一个看起来似乎还不怎么成熟的项目,却有着让很多成熟项目都汗颜的文档,其包括了安装指南、基本教程、以及一份近300页的全面用户指南。这对于用户来说是非常友好的,同时也说明了Gradle的开发者对这个项目非常有信心,要知道编写并维护文档可不是件轻松的工作,对于Gradle这样未来仍可能发生很大变动的项目来说尤为如此。
类似于Maven的pom.xml文件,每个Gradle项目都需要有一个对应的build.gradle文件,该文件定义一些任务(task)来完成构建工作,当然,每个任务是可配置的,任务之间也可以依赖,用户亦能配置缺省任务,就像这样:
defaultTasks 'taskB'



t
task taskA << {
 
    println "i'm task A"
}
}



t
task taskB << {
 
    println "i'm task B, and I depend on " + taskA.name
}
}



t
taskB.dependsOn taskA


运行命令$ gradle -q之后(参数q让Gradle不要打印错误之外的日志),就能看到如下的预期输出:
i'm task A
i
i'm task B, and I depend on taskA


这不是和Ant如出一辙么?的确是这样,这种“任务”的概念与用法与Ant及其相似。Ant任务是Gradle世界的第一公民,Gradle对Ant做了很好的集成。除此之外,由于Gradle使用的Grovvy脚本较XML更为灵活,因此,即使我自己不是Ant用户,我也仍然觉得Ant用户会喜欢上Gradle。
依赖管理和集成Maven仓库
我们知道依赖管理、仓库、约定优于配置等概念是Maven的核心内容,抛开其实现是否最优不谈,概念本身没什么问题,并且已经被广泛学习和接受。那Gradle实现了这些优秀概念了么?答案是肯定的。
先看依赖管理,我有一个简单的项目依赖于一些第三方类库包括SpringFramework、JUnit、Kaptcha等等。原来的Maven POM配置大概是这样的(篇幅关系,省略了部分父POM配置):
<properties>
 
        <kaptcha.version>2.3</kaptcha.version>
 
    </properties>



    <dependencies>
 
        <dependency>
 
            <groupId>com.google.code.kaptcha</groupId>
 
            <artifactId>kaptcha</artifactId>
 
            <version>${kaptcha.version}</version>
 
            <classifier>jdk15</classifier>
 
        </dependency>
 
        <dependency>
 
            <groupId>org.springframework</groupId>
 
            <artifactId>spring-core</artifactId>
 
        </dependency>
 
        <dependency>
 
            <groupId>org.springframework</groupId>
 
            <artifactId>spring-beans</artifactId>
 
        </dependency>
 
        <dependency>
 
            <groupId>org.springframework</groupId>
 
            <artifactId>spring-context</artifactId>
 
        </dependency>
 
        <dependency>
 
            <groupId>junit</groupId>
 
            <artifactId>junit</artifactId>
 
        </dependency>
 
    </dependencies>
然后我将其转换成Gradle脚本,结果是惊人的:
dependencies {
 
    compile('org.springframework:spring-core:2.5.6')
 
    compile('org.springframework:spring-beans:2.5.6')
 
    compile('org.springframework:spring-context:2.5.6')
 
    compile('com.google.code.kaptcha:kaptcha:2.3:jdk15')
 
    testCompile('junit:junit:4.7')
}
}
注意配置从原来的28行缩减至7行!这还不算我省略的一些父POM配置。依赖的groupId、artifactId、 version,scope甚至是classfier,一点都不少。较之于Maven或者Ant的XML配置脚本,Gradle使用的Grovvy脚本杀伤力太大了,爱美之心,人皆有之,相比于七旬老妇松松垮垮的皱纹,大家肯定都喜欢少女紧致的脸蛋,XML就是那老妇的皱纹。
关于Gradle的依赖管理起初我有一点担心,就是它是否有传递性依赖的机制呢?经过文档阅读和实际试验后,这个疑虑打消了,Gradle能够解析现有的Maven POM或者Ivy的XML配置,从而得到传递性依赖的信息,并且引入到当前项目中,这实在是一个聪明的做法。在此基础上,它也支持排除传递性依赖或者干脆关闭传递性依赖,其中第二点是Maven所不具备的特性。
自动化依赖管理的基石是仓库,Maven中央仓库已经成为了Java开发者不可或缺的资源,Gradle既然有依赖管理,那必然也得用到仓库,这当然也包括了Maven中央仓库,就像这样:
repositories {
 
    mavenLocal()
 
    mavenCentral()
 
    mavenRepo urls: "http://repository.sonatype.org/content/groups/forge/"
}
}
这段代码几乎不用解释,就是在Gradle中配置使用Maven本地仓库、中央仓库、以及自定义地址仓库。在我实际构建项目的时候,能看到终端打印的下载信息,下载后的文件被存储在USER_HOME/.gradle/cache/ 目录下供项目使用,这种实现的方法与Maven又是及其类似了,可以说Gradle不仅最大限度的继承Maven的很多理念,仓库资源也是直接拿来用。
Gradle项目使用Maven项目生成的资源已经不是个问题了,接着需要反过来考虑,Maven用户是否能够使用 Gradle生成的资源呢?或者更简单点问,Gradle项目生成的构件是否可以发布到Maven仓库中供人使用呢?这一点非常重要,因为如果做不到这一点,你可能就会丢失大量的用户。幸运的是Gradle再次给出了令人满意的答案。使用Gradle的Maven Plugin,用户就可以轻松地将项目构件上传到Maven仓库中:
apply plugin: 'maven'
.
...
u
uploadArchives {
 
    repositories.mavenDeployer {
 
        repository(url: "http://localhost:8088/nexus/content/repositories/snapshots/") {
 
            authentication(userName: "admin", password: "admin123")
 
            pom.groupId = "com.juvenxu"
 
            pom.artifactId = "account-captcha"
 
        }
 
    }
}
}
在上传的过程中,Gradle能够基于build.gradle生成对应的Maven POM文件,用户可以自行配置POM信息,比如这里的groupId和artifactId,而诸如依赖配置这样的内容,Gradle是会自动帮你进行转换的。由于Maven项目之间依赖交互的直接途径就是仓库,而Gradle既能够使用Maven仓库,也能以Maven的格式将自己的内容发布到仓库中,因此从技术角度来说,即使在一个基于Maven的大环境中,局部使用Gradle也几乎不会是一个问题。
约定优于配置
如同Ant一般,Gradle给了用户足够的自由去定义自己的任务,不过同时Gradle也提供了类似Maven的约定由于配置方式,这是通过Gradle的Java Plugin实现的,从文档上看,Gradle是推荐这种方式的。Java Plugin定义了与Maven完全一致的项目布局:

src/main/java

src/main/resources

src/test/java

src/test/resources
区别在于,使用Groovy自定义项目布局更加的方便:
sourceSets {
 
    main {
 
        java {
 
            srcDir 'src/java'
 
        }
 
        resources {
 
            srcDir 'src/resources'
 
        }
 
    }
}
}
Gradle Java Plugin也定义了构建生命周期,包括编译主代码、处理资源、编译测试代码、执行测试、上传归档等等任务:

Figure 1. Gradle的构建生命周期
相对于Maven完全线性的生命周期,Gradle的构建生命周期略微复杂,不过也更为灵活,例如jar这个任务是用来打包的,它不像Maven那样依赖于执行测试的test任务,类似的,从图中可以看到,一个最终的build任务也没有依赖于uploadArchives任务。这个生命周期并没有将用户限制得很死,举个例子,我希望每次build都发布 SNAPSHOT版本到Maven仓库中,而且我只想使用最简单的$ gradle clean build命令,那只需要添加一行任务依赖配置即可:
build.dependsOn 'uploadArchives'
由于Gradle完全是基于灵活的任务模型,因此很多事情包括覆盖现有任务,跳过任务都非常易于实现。而这些事情,在Maven的世界中,实现起来就比较的麻烦,或者说Maven压根就不希望用户这么做。
小结
一番体验下来,Gradle给我最大的感觉是两点。其一是简洁,基于Groovy的紧凑脚本实在让人爱不释手,在表述意图方面也没有什么不清晰的地方。其二是灵活,各种在Maven中难以下手的事情,在Gradle就是小菜一碟,比如修改现有的构建生命周期,几行配置就完成了,同样的事情,在Maven中你必须编写一个插件,那对于一个刚入门的用户来说,没个一两天几乎是不可能完成的任务。
不过即使如此,Gradle在未来能否取代Maven,在我看来也还是个未知数。它的一大障碍就是Grovvy,几乎所有 Java开发者都熟悉XML,可又有几个人了解Groovy呢?学习成本这道坎是很难跨越的,很多人抵制Maven就是因为学起来不容易,你现在让因为一个构建工具学习一门新语言(即使这门语言和Java非常接近),那得到冷淡的回复几乎是必然的事情。Gradle的另外一个问题就是它太灵活了,虽然它支持约定优于配置,不过从本文你也看到了,破坏约定是多么容易的事情。人都喜欢自由,爱自定义,觉得自己的需求是多么的特别,可事实上,从Maven的流行来看,几乎95%以上的情况你不需要自行扩展,如果你这么做了,只会让构建变得难以理解。从这个角度来看,自由是把双刃剑,Gradle给了你足够的自由,约定优于配置只是它的一个选项而已,这初看起来很诱人,却也可能使其重蹈Ant的覆辙。Maven在Ant的基础上引入了依赖管理、仓库以及约定优于配置等概念,是一个很大的进步,不过在我现在看来,Gradle并没有引入新的概念,给我感觉它是一个结合Ant和Maven理念的优秀实现。
如果你了解Groovy,也理解Maven的约定优于配置,那试试Gradle倒也不错,尤其是它几乎能和现有的Maven系统无缝集成,而且你也能享受到简洁带来的极大乐趣。其实说到简洁,也许在不久的将来Maven用户也能直接享受到,Polyglot Maven在这方面已经做了不少工作。本文完全基于Maven的视角介绍Gradle这一构建工具的新秀,不过限于篇幅原因,无法深入Gradle的方方面面,例如Gradle也支持多模块构建,它提供了GUI操作界面,支持Grovvy(理所当然)和Scala项目等等。有兴趣的读者可以自行进一步了解。

*******************************************************
2009-03-27
Java构建工具的未来
         不久之前博客Adam Bien写了关于一篇关于老话题:Ant或者Maven的文章,文中有写道“Maven的真正厉害之处是它的依赖管理(dependency management),要做许多工作才能让Ant的依赖管理达到Maven的程度……”文章对Maven似乎有所偏爱,这引起来了Adam Pohorecki的争论,并由此进一步谈到了Java构建工具的未来:
         尽管Ant没有内置的依赖管理是个事实,但是将Ivy整合到你build.xml中还是很简单的,所以我认为Adam Bien所说的“许多工作”是个误导。
         如果要我在Ant和Maven之间选择,我会选择前者。我也理解为什么很多人喜欢将Maven作为他们首选的构建工具,因为它有构建脚本,只需要几行代码来配置就可以有许多功能:依赖管理、内置的编译和打包应用的任务、与Jetty的集成、干净的项目web网址,与cobertura的集成、pmd或者findbugs。在这种情况下,如果你启动的项目非常常规(使用Spring & Hibernate的应用),Maven就是非常好的选择。
         没有人想写构建脚本,因为这种代码没有任何真正的商业价值。如果没有遇到问题,你会觉得Maven真的很棒。但也许你的项目不是常规的,也许你使用的插件彼此冲突,在Maven这样的构建系统中有许多失败的地方,而且经常你很难找到它们的来源并修复它们。
         Ant比Maven更值得选择的优点并不明显。而且Ant用手来编写所有的构建代码确实很遭罪。但一旦搞定之后,构建脚本就真正成了你的代码。而且在运行出现问题时,你可以检查代码并修改之,不必像无头苍蝇一样无迹可寻。
         但是,Maven和Ant就只是我们的选择么?是否还有比它们更好的选择?在过去的几年中,我们看到很多项目,他们使用的工具不再使用XML来定义构建逻辑,而是真正的编程语言像Groovy、Ruby、Python,它们经常允许依赖管理。这里有几个:GRADLE、Gant、Kundo、 Raven、 Buildr。
         我最爱的构建工具是Gant,它至今也不过发布了几个月而已。Gant基本是一种Groovy的方式调用了Ant任务,比较起老旧的build.xml它有很多优点。通过使用真正的编程语言而不是XML,许多本来在XML中很是枯燥的任务变得简单:将通用代码提取为方法、循环、条件逻辑。实际上,XML并非编程语言也不应当被当成编程语言来使用。使用像Groovy或者Ruby这样的语言来构建脚本更加简洁、易懂,而且杂乱冗余的代码更少,结构上也更清晰。
         在我看来,在Java环境构建自动化的未来是Gradle,或者是另外一些有相似特性的工具。Gradle是一种我所喜欢的构建脚本:如果是简单、标准的项目你只需要几行配置就可以搞定。它甚至在不使用Maven或者Ivy套件库的情况下允许可传递的依赖管理(transitive dependency management)。当我们第一次知道“依赖管理”,是用ivy.xml或者pom.xml写下我们的依赖,然后不得不安装一个独立的仓库(repository )来存储这些不能在Maven库中找到的依赖,不得不修补pom.xml文件,因为有些没有声明它们的依赖。现在这一切可以成为历史了,我们有DM,只要在SVN库中存储我们需要的libs,然后在用到的时候转到真正的DM就可以了。
         而且,如果是大的项目,除了其他特性之外Gradle拥有对多项目构建的第一类(first-class)支持,(比如你可以规定项目依赖,当你构建一个附属项目时,它的依赖也会被构建好)。Gradle还有其他很多特性,你可以在官网的用户指南上寻找,大概100多页。我的意思是如果你肯花点时间来阅读,你就会发现Gradle将会让你的开发变得多么地容易。
         但我还是不得不承认,Gradle也许不适合“产品理念”,毕竟项目开发还是个新事物。但如果你想找个更好的工具来替代Ant,Gradle就是。如果你想找工具代替Maven,也许还得等几个月,因为Gradle目前还没有支持许多Maven用户所依赖的特性,比如项目网址、为主要的IDEs生成项目文档。
         概括来说,虽然对自动化构建而言没有一种方法解决所有问题的解决方案,但正在进步的新工具却在努力做到这点。既可以按照惯例来构建,也可以按照你自己想要的方法来构建,Gradle在这两方面既吸引了Ant也吸引了Maven的fans。在我看来,未来构建脚本是用像Groovy或者Ruby这样的编程语言来编写的,而Gradle将在工具中占据重中之重。

Maven实战——Gradle,构建工具的未来?的更多相关文章

  1. [Gradle] Gradle 构建工具的未来

    转载地址:http://www.infoq.com/cn/news/2011/04/xxb-maven-6-gradle Maven面临的挑战 软件行业新旧交替的速度之快往往令人咂舌,不用多少时间,你 ...

  2. Android Gradle 构建工具(Android Gradle Build Tools)是什么?

    转载地址:http://mrfu.me/android/2015/07/17/New_Android_Gradle_Build_Tools/ 译者地址:[翻]一览新的 Android Gradle 构 ...

  3. 一览新的 Android Gradle 构建工具:新的 DSL 结构 和 Gradle 2.5

    译者地址:[翻]一览新的 Android Gradle 构建工具:新的 DSL 结构 和 Gradle 2.5 原文:First Look at New Android Gradle Build To ...

  4. 大神所写的深度好文---Gradle 构建工具

    什么是构建工具? 我们大家都知道 Gradle 是一种构建工具,那么什么是构建工具呢? 网上一大堆的文字解释我觉得很难理解,这里我以咱们 Android 开发来举个例子吧. 我们以前开发都是用 Ecl ...

  5. AS Gradle构建工具与Android plugin插件【大全】

    Android plugin version 与 gradle version 的关系 Gradle是一种构建工具,它通过编写一个名为build.gradle的脚本文件对项目进行设置,再根据这个脚本对 ...

  6. Android NDK开发 Android Studio使用新的Gradle构建工具配置NDK环境(一)

    本文主要讲述了如何如何在Android Studio使用新的Gradle构建工具配置NDK环境,现在把相关的步骤整理出来分享给Android程序员兄弟们,希望给他们在配置NDK环境时带来帮助. 从An ...

  7. 24 使用Maven 或 Gradle构建groovy

    1       使用Maven 或 Gradle构建groovy 1.1  使用maven构建groovy pom.xml file. <dependencies>     ... oth ...

  8. 学习笔记——Maven实战(六)Gradle,构建工具的未来?

    Maven面临的挑战 软件行业新旧交替的速度之快往往令人咂舌,不用多少时间,你就会发现曾经大红大紫的技术已经成为了昨日黄花,当然,Maven也不会例外.虽然目前它基本上是Java构建的事实标准,但我们 ...

  9. gradle 构建工具,与Ant Maven关系

    1   基本概念 gradle是一个基于Apache ant 和apache maven概念的项目自动化建构工具.它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的xml.当前其支持 ...

随机推荐

  1. Latex使用的注意事项

    CTEX : CTeXDownload latex中的图片格式主要就2种 pdf 和 eps.如果要用pdflatex编译,那么自然选择pdf,如果用latex编译,自然用eps.本人论文中的图片来源 ...

  2. Spring Boot 集成Shiro和CAS

    Spring Boot 集成Shiro和CAS 标签: springshirocas 2016-01-17 23:03 35765人阅读 评论(22) 收藏 举报  分类: Spring(42)  版 ...

  3. Spark(十二)--性能调优篇

    一段程序只能完成功能是没有用的,只能能够稳定.高效率地运行才是生成环境所需要的. 本篇记录了Spark各个角度的调优技巧,以备不时之需. 一.配置参数的方式和观察性能的方式 额...从最基本的开始讲, ...

  4. 如何使用Android studio打开eclipse项目

    转: http://blog.csdn.net/zcw93219/article/details/50770445

  5. StackPanel

    StackPanel 的 HorizontalAlignment 属性和 VerticalAlignment 属性 默认情况下,这两个属性都被设置为 Stretch.

  6. 【机器学习】Logistic Regression 的前世今生(理论篇)

    Logistic Regression 的前世今生(理论篇) 本博客仅为作者记录笔记之用,不免有非常多细节不正确之处. 还望各位看官能够见谅,欢迎批评指正. 博客虽水,然亦博主之苦劳也. 如需转载,请 ...

  7. Python操作记录

    1.写入中文出错,需要执行 reload(sys) sys.setdefaultencoding('utf8') 2.json.dump中文写入为\xxxx ensure_ascii=False

  8. 有用的java工具

    1.Jsoup html页面解析 2.FastJson java中json处理工具,类似于gson 3.jodd 类似于apache commons的一些常用工具集 4.Selenium IDE we ...

  9. Android Activity 及其子类

    本文内容 ListActivity TabActivity LauncherActivity ExpandableListActivity PerferenceActivity 这些类都继承 Acti ...

  10. Eclipse导入git上的maven web项目 部署 - lpshou

    http://www.tuicool.com/articles/fqm2Qf   推酷 文章 微博 主题 站点 活动 应用 周刊 登录   Eclipse导入git上的maven web项目 部署 - ...