当前位置: 首页 > 技术与资源 > 技术分享 > 正文

Java项目构建新型利器——Gradle

2016-01-14 11:18:53

作者:阳春泉新炬网络高级技术专家。


多年来,建立了简单的编译和打包软件需求。但现代软件开发的格局发生了变化,因此需要构建自动化。今天,项目涉及到大型的和多样化的一系列相关软件,将多种编程语言,并应用广泛的测试策略。随着敏捷实践的兴起,构建必须支持早期的集成代码并且容易交付测试环境和生产环境。


建立构建工具经常达不到这些目标。有多少次你目不转睛的看着XML来找出一个构建是如何运作的?为什么不能更容易添加自定义逻辑构建?通常,当添加到构建脚本,你无法实现一个解决方案或很好的编辑脚本。我能感觉到你的痛苦,因此必须有一个在表现力和可维护性上更好的方法完成这些事情。——这就是Gradle。


Gradle是下一个基于java的循序渐进的构建工具。它汲取Ant和Maven教训并借鉴他们的优点。随着build-by-convention方法的出现,它允许以声明的方式建模您的问题域,使用一个强大的和富有表现力的领域特定语言(DSL)在Groovy中实现,而不是XML。因为Gradle是一个本地JVM,它允许您使用你最熟悉语言编写自定义逻辑,无论是Java或Groovy。


Java构建工具的进化


让我们看看构建工具多年的发展历程。两个主导构建Java项目工具:Ant和Maven。在过去的几年,这两个工具都明显改善和扩展他们的特性集,但尽管都非常受欢迎,已经成为行业标准,他们有一个弱点:必须建立逻辑描述的XML文件。XML非常适合描述分层数据,但低于表达程序流和条件逻辑。作为一个构建脚本过于复杂,那么维护构建代码就变成了噩梦。


Ant的第一个官方版本是在2000年。每个元素的工作可以组合和重用。多个目标可以链接到单个的工作单元合并成完整的工作流。例如,您可能有一个目标来编译Java源代码,另一个用于创建一个JAR文件包的类文件。JAR文件只有当你编译源代码后才能构建。在如何构建项目上,Ant不给任何指导。虽然它允许最大的灵活性, Ant会使每个构建脚本独特而难以理解。项目所需的外部库通常签入到版本控制,因为没有把它们从一个中央位置自动载入的机制。早期版本的Ant需要大量的规则,以避免重复的代码。其扩展机制太弱。因此,复制和粘贴糟糕的代码是唯一可行的选择,统一项目布局,企业需要实施标准。


Maven 1在2004年7月发布,它试图缓解这一过程。提供了一个标准化的项目和目录结构,以及依赖关系管理。不幸的是,自定义逻辑很难实现。如果你想打破Maven的惯例,编写一个插件,称为Mojo,通常是唯一的解决方案。Mojo可能意味着一个简单的、容易的和可观的方法来扩展Maven;实际上,Maven插件过于繁琐复杂。


随后,Ant赶上Maven通过引入Apache Ivy依赖管理,可完全与Ant集成声明在为您的项目编译和打包过程中所需的指定依赖项。Maven的依赖管理器,以及Ivy,支持解决传递依赖关系。一个传递依赖的一个典型的例子是XML解析库Xerces,需要正确的XML api库函数。2005年10月发布了Maven 2,进一步约定优于配置的概念。项目由多个模块定义他们的相互依赖关系。


我们看到从使用XML转向更具表达性和可读的语言来定义构建。一个构建工具,进行这个想法是Gant,DSL的Ant用Groovy编写的。使用甘特图,用户现在可以将Groovy特性与他们现有知识的Ant,而不必编写XML。即使它不是核心Maven项目的一部分,类似的方法是提出的项目Maven通晓多国语言,使您可以编写您的构建定义逻辑,这是项目对象模型(POM)文件,在Groovy中,Ruby,Scala或Clojure。


我们在应用程序开发的一个新时代的尖端:通晓多种语言的编程。当今的许多应用程序整合多种编程语言,每一种都是最适合实现一个特定的问题领域。也不是什么罕见的项目使用的客户端JavaScript这样的语言与混合通信,多语种等后端Java,Groovy,和Scala,进而使调用c++遗留应用程序。这都是正确的工具来完成工作。尽管结合多种编程语言的好处,您的构建工具需要流利的支持这一基础设施。JavaScript需要合并,简化和压缩,遗留代码而服务器端需要编译、打包和部署。


Gradle正好适合代构建工具和满足许多需求的现代构建工具(图1),它提供了一个富有表现力的DSL,约定优于配置的方法和强大的依赖关系管理。放弃XML和介绍了动态语言Groovy定义构建逻辑,这是一正确的举措。听起来令人信服的,不是吗?


阳春泉 - Java项目构建新型利器——Gradle1

图 1:它结合了其他构建工具的最佳特性。


为什么选择Gradle?


如果你是一名开发人员,自动化您的项目是你的日常业务的一部分。你不想把您的构建代码像任何其他的软件一样可以扩展,测试,和维护吗?Gradle构建脚本是声明性的,可读性强的,清楚地表达自己的意图。用Groovy编写代码,而不是XML,显著减少了构建脚本的大小并且更可读(参见图2)。


阳春泉 - Java项目构建新型利器——Gradle2

图2:Maven和Gradle之间比较构建脚本的大小和可读性。


Gradle令人印象深刻的是编写更少的代码却能达到同样的目标。其他诸如Maven之类的构建工具提出项目布局相互独立。Gradle的DSL允许灵活性,适应非常规项目结构。永远不会改变一个运行的系统。你的团队已经花费了大量的时间建立基础设施项目的构建代码。Gradle并不强迫你完全迁移所有现有的构建逻辑。良好的集成与其他工具,比如Ant和Maven是它的优先级列表的顶部。市场似乎注意到它。流行的开源项目,比如Groovy和Hibernate完全转向Gradle为骨干的构建。每个Android项目附带Gradle作为默认的构建系统。它也影响了商业市场。EADS公司Orbitz,Software AG拥护它,这些只是其中一部分。VMware,Spring和Grails背后的公司都选择并投资了它。他们的许多软件产品,比如Spring框架和Grails,都相信它是一个可以相信的构建工具。


它的引人注目的特性集


让我们仔细看看它与竞争对手有什么不同:其引人注目的特性集(参见图3)。总而言之,它是一个企业级构建系统,由一个声明式和富有表现力的Groovy DSL。它结合了灵活性和毫不费力的可扩展性和约定优于配置的想法并支持传统的依赖关系管理。它是由一个专业服务公司(Gradleware)和强大的社区参与完成,它是许多开放源码项目和企业构建解决方案的第一选择。


阳春泉 - Java项目构建新型利器——Gradle3

图3:它的引人注目的特性集。


灵活的约定


Gradle的一个伟大的想法是让你为项目指南和合理的默认值。每一个Java项目Gradle知道源和测试类文件应该住在哪里,以及如何编译你的代码,运行单元测试,生成Javadoc报告,并创建一个代码的分布。所有这些任务都是完全集成到构建生命周期。如果你坚持惯例,只有最小的配置工作。事实上,你的构建脚本是一个一行程序。图4为Java项目说明了Gradle介绍约定和生命周期任务。


阳春泉 - Java项目构建新型利器——Gradle4

图4:在Java项目构建按照惯例Gradle,合理的默认值。改变默认值是容易的,通过公约性质。


提供缺省任务的上下文中有意义的Java项目。例如,您可以编译Java源代码,生产运行测试,组装一个JAR文件。每一个Java项目开始于一个标准的目录布局。它定义了在哪里可以找到源代码,生产资源文件和测试代码。公约属性用于改变默认值。


同样的概念也适用于其他项目原型像Scala,Groovy web项目,和许多更多。Gradle调用这个概念构建按照惯例。构建脚本开发人员不需要知道这是如何工作的。相反,您可以专注于需要配置。在Maven Gradle的约定是相似的,但他们不让你感觉固步自封。Maven是非常固执己见;它提出一个项目只包含一个Java源代码目录,只产生一个单独的JAR文件中。这对许多企业项目不一定是现实。它允许您轻松地打破惯例。在光谱的另一端, Ant不给你很多指导如何结构构建脚本,以便最大程度的灵活性。Gradle将中间地带通过提供约定的结合能够很方便地改变它们。


健壮的和强大的依赖关系管理


几乎每个Java项目都会用到开源框架。同时,对于具有多个子模块的项目来说,项目之间也会有所依赖。所以,管理项目中对开源框架和其他模块的依赖是每个项目必须面对的问题。同时,Gradle也使用Repository来管理依赖。


Maven提出了使用Repository来管理Jar包,Ant也提供了使用Ivy来管理jar包。Gradle提供了对所有这些Respository的支持,可以从Gradle的官方文档上了解更详细的信息。


Gradle沿用Maven的依赖管理方法,通过groupId、name和version到配置的Repository里寻找指定的Jar包。同样,它也提供了和Maven一样的构建生命周期,compile、runtime、testCompile和testRuntime分别对应项目不同阶段的依赖。


对于多模块的项目,项目中的某些模块需要依赖于其他模块,前面提到在初始化阶段,Gradle为每个模块都创建了一个Project对象,并且可以通过模块的名字引用到该对象。在配置模块之间的依赖时,使用这种方式可以告诉Gradle当前模块依赖了哪些子模块。


除了项目需要依赖之外,构建脚本本身也可以有自己的依赖。当使用一个非Gradle官方提供的插件时,就需要在构建脚本里指定其依赖,当然还需要指定该插件的Repository。在Gradle中,使用buildscript块为构建脚本配置依赖。


可伸缩的构建


对于一些公司来说,一个大型项目与数以百计的模块就是现实。构建和测试小代码更改会耗费很多时间。你可能知道从个人经验,删除旧的类和资源通过运行清理任务是一种自然反应。时常,你得到了你的构建工具不是捡的变化及其相关性。你需要的是一个足够聪明的工具只有重建的部分软件,实际上改变了。它支持增量构建通过指定任务的输入和输出。你可靠地找出哪些任务需要跳过,建造,或部分重建。相同的概念转化为multimodule项目,称为部分构建。因为您的构建明显定义子模块之间的依赖关系,它只负责重建必要部分。


自动化单元、集成和功能测试是构建过程的一部分。独立的短时间运行的类型的测试是有意义的,需要设置运行资源或外部依赖。它支持并行测试执行。这个特性是完全可配置的,确保你实际上利用处理器的核心。巴克并不到此为止。Gradle将支持分布测试执行多台机器在未来版本。读你的Twitter的日子长之间构建已经一去不复返了。


开发人员在开发期间多次运行构建。这意味着每次开始一个新的Gradle过程,加载所有的内部依赖关系,和运行构建逻辑。你会注意到通常要花几秒钟之前脚本开始执行。改善启动性能,它可以以守护进程模式运行。在实践中,Gradle命令叉一个守护进程,这不仅执行构建,也一直在后台运行。随后构建调用将利用现有的守护进程来避免启动成本。因此,你会发现更流畅的初始构建执行。


毫不费力的可扩展性


大多数企业构建不一样,也不解决同样的问题。一旦你设置的初始阶段基本脚本,你想实现自定义的逻辑。Gradle不是固执己见的方式实现代码。相反,它为您提供了不同的选项可供选择,根据您的特定的用例。最简单的方法来实现自定义逻辑是通过编写一个任务。任务可以直接定义在构建脚本中没有特殊的仪式。如果你觉得复杂,你可能想要探索的选择一个自定义的任务,允许编写逻辑在类定义,代码结构简单,易于维护。如果你想在构建和项目之间共享可重用的代码,插件是你最好的朋友。代表Gradle最强大的扩展机制,插件给你完全访问它的API,可以编写,测试,和分布式像任何其他的软件。编写一个插件非常简单,不需要很多额外的描述符。


与其它构建工具的集成


Gradle扮演好其前任Ant、Maven、Ivy,如图5所示。


阳春泉 - Java项目构建新型利器——Gradle5

图5:它提供了深度集成与其他构建工具和开门逐步迁移现有Ant或Maven构建。


如果你来自Ant,它并不强迫你迁移完整的基础设施建设。相反,它允许您导入现有的构建逻辑和重用标准的Ant任务。Gradle构建100%兼容Maven和Ivy存储库。您可以检索依赖和发布自己的构件。Gradle为现有的Maven构建提供了一个转换器,可以构建逻辑转换成Gradle构建脚本。


现有的Ant脚本可以导入Gradle构建无缝结合和作为你使用任何其他外部Gradle脚本。Ant将目标直接映射到Gradle任务在运行时。Gradle附带Ant库和公开了一个助手类脚本叫做AntBuilder,这充分混合进它的DSL。它仍然看起来就像Ant的XML,但没有尖括号。Ant用户会感觉得心应手,因为他们不需要过渡到Gradle语法。从Ant迁移到Gradle也是显而易见的。你可以把婴儿步骤通过重用现有的Ant逻辑,而在同一时间使用它的好处。


Gradle旨在达成类似的深度与Maven集成。在撰写本文时,尚未实现。从长远来看,Maven酸盐和插件将被视为Gradle原住民。Maven和Ivy库已成为今天的基础设施建设的一个重要组成部分。想象一下这样一个世界没有Maven中央帮助访问特定版本的你最喜欢的项目依赖项。从存储库中检索依赖只是故事的一部分;出版同样重要。与配置,它可以上传您的项目工件的公司或公共消费。


更大的图景:持续交付


能够构建源代码只是软件交付过程的一个方面。更重要的是,你能释放出你的产品在生产环境中交付业务的价值。在这个过程中,你想要运行测试,构建分布,分析代码质量的目的,可能提供一个目标环境部署。


整个过程自动化有很多好处。首先,交付软件手动缓慢,容易出错,而且非常伤脑筋。我相信我们每一个人都讨厌漫长的夜晚由于部署出错。随着敏捷方法的兴起,开发团队能够更快地交付软件。发布周期为两个或三个星期一次已成为常态。你希望能够释放软件通过选择目标环境简单地按下一个按钮。实践像自动化测试,CI和部署注入持续交付的一般概念。


让我们看看它如何帮助你的项目从建立到部署。它可以使您能够自动化的许多任务需要实现持续交付,他们编译源代码,部署交付,或者调用外部工具,帮助你实现这个过程。


自动化部署项目的构建


持续交付介绍部署管道的概念,也称为构建管道。部署管道代表了技术实现的过程获得软件版本控制到生产环境中。过程由多个阶段,如图6所示。


阳春泉 - Java项目构建新型利器——Gradle6

图6:一个部署阶段的管道。


•  提交阶段:报告技术项目的健康水平。这个阶段的工作是编译代码,运行测试,执行代码分析,和准备的分布。


•  自动化验收测试阶段:断言,通过运行自动化测试满足功能性和非功能性需求。


•  手动测试阶段:验证系统实际上是在测试环境中使用。通常,这个阶段包括QA人员验证用例需求。


•  发布阶段:向最终用户交付软件打包分布或将它部署到生产环境。


•  编译的代码


•  运行单元测试和集成测试


•  执行静态代码分析和生成测试覆盖率


•  创建分布


•  配置目标环境


•  部署交付


•  自动化功能测试


图7显示了在每个阶段的任务。虽然没有硬性规则,阻止你跳过特定的任务,还是建议您遵循秩序。例如,您可以决定编译你的代码,创建分布,并将其部署到目标环境,但不运行任何测试和静态代码分析。然而,这样做会增加未被发现的缺陷代码和质量差代码风险。


阳春泉 - Java项目构建新型利器——Gradle7

图7:构建管道的任务执行阶段。


例如基础设施配置、自动部署和Smoke测试也可以应用于释放阶段。在实践中,将这些技术应用到生产环境中比在一个测试环境中更复杂。在生产环境中,您可能需要处理集群和分布式服务器基础设施,零宕机,和自动回滚到以前的版本。

上一篇:Elasticsearch与hadoop比较
下一篇:对一次drop分区引发性能问题的思考