实战Gradle(txt+pdf+epub+mobi电子书下载)


发布时间:2020-12-07 12:32:58

点击下载

作者:李建,杨柳,等

出版社:电子工业出版社有限公司

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

实战Gradle

实战Gradle试读:

前言

当我以软件开发开始我的职业生涯时,我完全没有意识到对项目自动化的需求。我选择IDE作为开发工具,它可以让我运行所有需要[1]的任务,并完成自动化软件开发环节。2003年,Rainer Sawitzki,我所在项目的一个外部咨询师,他向我介绍了Ant。我觉得它简直太神奇了,Ant能够通过已有的功能帮助我描述大部分自动化逻辑,并按照预定义的顺序执行。尽管定义语言是XML(曾经有那么一段时间XML还是很流行的),通过给不同的目标平台构建产品,给Web容器编写部署逻辑和配置持续集成服务器,我的野心开始变得越来越大。

从那时起,自动化的需求发生了巨大的变化。项目变得越来越大,也越来越复杂。部署和交付模式已经远比之前麻烦。这些年为了满足自动化需求,我探索了许多其他类型的构建工具,但我总是会发现有不合逻辑的地方。许多开发者接受和维持这种现状,因此给他们留下[2]了一些痛苦的经历。很少有话题去真正地讨论这个问题,而不仅仅是赞成或者反对构建工具,以及为什么如此地不喜欢构建工具。本书的目的并不是要说服你从当前的构建工具切换到Gradle。如果你很满意你的配置方式(不管你用的什么),无论怎样,要坚持住。而我会更多地谈论Gradle带来的巨大创新,以及与现有解决方案的对比。我诚心地请求你做出自己的判断。

在我的头脑里,我带着一种特殊的目的开始写这本书:教给你Gradle的核心概念,但不止于此。在一个拥抱持续集成和持续交付实践的软件开发世界,你必须考虑一个问题,那就是将构建系统集成到工具的生态系统中。但愿,我在这本书里找到了平衡点。如果你有任何问题、评论或者想法,我都非常愿意去倾听。你的反馈也许会促使我去写第二版书或者附加新的内容。请随时向我发送电子邮件或者在Manning的论坛上和我联系。

就和所有的书一样,纸张的数量是有限的。为了控制本书的讨论范围,我不得不去掉一部分我原本打算写进去的内容(这是我的第一本书,带着初为作者的天真,我以为我可以将所有的内容都写进去)。关于本书的源代码,你可以在https://github.com/bmuschko/gradle-in-action-source中找到,里面扩展了书中的一些内容,也列出了其他代码样例和资料的参考文献。我希望你可以和我享受写这本书一样,享受阅读这本书。[1]再次感谢你在工作中交给我面向对象的思想。你是我的一位伟大导师。[2]这个话题就像对比Windows和Linux或者Web应用框架。致谢

当考虑写一本书时,你完全不知道有多少工作需要去做。可以肯定地说,它绝对会长时间掌控着你的生活。一段时间之后,写作的部分会变得简单一些。困难的是要坚持每天写。在没有支持、鼓励和别人帮助的情况下,是完全不可能的。

2010年,我开始给前雇主评估Gradle能否作为一个Maven项目的替代品。如果没有Jonathan Bodner发起的这次尝试,我很有可能无法完成这次评估。Jonathan Bodner是我的一个老朋友,我非常钦佩他在技术方面的洞察力,是他激起了我对Gradle的热情,让我深深地融入到这个社区,并开始实现我自己的插件。

在开始写书之前,我已经担任多年Manning出版社所出版书籍的技术审查员。这一切都开始于我与Dan Allen在No Fluff Just Stuff会议上的一次偶遇,他是Seam in Action(Manning,2008)的作者。在那次会议上,仅仅是跟他聊的这一会儿,就很快激起了我对他这份事业的热情,于是我开始帮助他审阅他的书籍。这次给别人审阅书的机会,让我第一次了解到写一本书的意义。而我其实一直都想要写一本书,但从来就没有找到合适的时间或者主题。Gradle给了我机会。感谢Dan,你的热情鼓励着我继续传递这只火炬,也鼓励着我点燃自己的火炬。

在开始写书之前,你首先要做的事情之一就是完成大纲和目录。David James是第一个阅读本书初稿的人,他是华盛顿地区Groovy用户组的组织者。感谢你对本书组织结构提供的独特观点,也感谢你对细节的一丝不苟,以及你的鼓励让这本书成为现实。

商业化图书的出版离不开背后做出贡献的人,这包括Manning出版社所有参与到本书出版中的每个人。Michael Stephens是第一个和我交谈的人,对于本书的思想,他很买账,也最终信任我能够做好这份工作。我的感激也要送给Cynthia Kane,她帮助我找到我自己的写作风格。我也想要感谢Jennifer Stout,我的发展编辑,他总是设法让我做到最好,让我以一种不同的方式去考虑整个文本段落,并忍受我的不耐烦,这对我的帮助非常大。还要感谢Manning的产品和市场团队一直的指导,它促使这本书成为现在这个样子。我知道你们做了大量的工作。

我还想要感谢Gradleware团队的成员以及Gradle社区创建了Gradle,并不断推进构建自动化的发展。你们持续不断的努力和对高质量产品的信仰,提高了全球正对构建恼火的大师的生活质量。特别要感谢René Gröschke和Luke Daley在技术方面的洞察力,以及他们对本书三分之一内容的审阅。我也非常感激Gradle的创始人,Hans Dockter,他帮助本书作序,以及对这本书给予早期认可,并通过Gradleware持续提供帮助。

感谢以下所有的手稿审阅人,他们向我提供了无价的反馈和对书中内容独特的观点:Andy Keffalas,BJ Peter DeLaCruz,Chris Grijalva,Chris Nauroth,Dominik Helleberg,Eric Wendelin,Iain Starks,John Moses,Jon Bodner,Marcin Nowina-Krowicki,Mayur S.Patil,Mehrdad Karjoo,Mohd Suhaizal Md Kamari,Nacho Ormeño,Nick Watts,Pawel Dolega,Rob Bugh,Robin Percy,Samuel Brown,Scott Bennett-McLeish,Steve Dickson,Tarin Gamberini,Wellington R.Pinheiro和Zekai Otles。也要感谢Barry Kern在手稿正式进入印刷之前,仔细地进行技术方面的校对。

特别要感谢Spencer Allain,Jonathan Keam和Robert Wenner通读了本书的每个章节,并在写书不同阶段向我提供了逐字逐句的修改建议和评论。要感谢Michael McGarr和Samuel Brown反复审阅书中关于持续交付和DevOps的内容,以及要感谢来自于JFrog的Baruch Sadogursky帮助我从技术的角度审阅了第14章,并在本书出版之前,就帮助推销这本书。我也想要感谢无情的Author Online论坛的用户不断地将书中的内容推向更高的层次。

写一本书需要做出牺牲,而且加剧了我人际关系的紧张程度。我想要感谢我的家人和朋友,他们在我不断朝着这个宏伟目标前进的时候,给予我支持、鼓励和理解。还有就是,以后出去玩的时候,我不会再去思考书中的内容了。

我深深地感激我的妻子Sarah对我无止境的支持以及她乐观的心态。她让我相信自己,让我在写作时学会休息,也忍受了大部分的日子里,我在晚上9:00点之前就睡了。没有你,写作带来的疲惫会远比现在多。第1部分Gradle介绍有效的项目自动化是促使软件成功交付给终端用户的关键因素。构建工具的选择不应该成为软件交付中的障碍;相反,它应该提供一种灵活且可持续的方式去塑造你的自动化需求。Gradle的核心能力就是提供一种易于理解且强大的工具,从端到端自动化你的项目。在第1章中,我们会讨论项目自动化的好处,以及它对于以可重复、可靠和便捷的方式开发和交付软件的影响。你将会学习到该构建工具的基本概念和组件,以及它们是如何与Ant和Maven一起工作的。通过对比它们的优缺点,你将会看到对下一代构建工具的需求。Gradle从已有构建工具中吸取经验,取其精华,并进一步提升。第2章将会介绍Gradle中那些引人注目的特性集。你将了解如何安装Gradle,学习如何写一个简单的构建脚本,并在命令行中运行它。简单的构建脚本到第2章就结束了。第3章会介绍一个真实世界中基于Java的Web应用程序。你将会学习到从编译、单元测试、打包到运行该样例程序所需要的全部配置。在第1部分结束时,你会对Gradle的表达力和灵活性有一定的感受。1 项目自动化介绍

本章涵盖

■ 理解项目自动化的好处

■ 了解不同类型的项目自动化

■ 考察构建工具的特性和架构

■ 探索构建工具实现的优点和缺点

Tom和Joe以软件开发人员的身份在Acme Enterprises公司工作,这是一家刚刚成立的公司,该公司提供一种免费的在线服务,帮助你在某个具体的领域中寻找最划算的交易。这家公司最近收到投资者的资金投入,目前正疯狂地朝着第一次发布前进。Tom和Joe正处于一个危急时刻。到下个月底,他们需要向投资者展现产品的第一个版本。两个开发人员都是有紧迫感的人,他们每天都能开发出新的特性。到目前为止,软件开发控制在规定的时间和预算之内,这让他们感到满意。首席技术官(CTO)时不时会过来拍拍他们的后背,生活非常的美好。然而,手动构建和错误构建以及整个交付的过程都严重影响他们的速度。结果是,整个团队不得不忍受着零散的编译问题、构建不一致的软件工件和失败的部署。这就是引入构建工具的原因。

本章会给出一个简单的介绍,告诉你为什么要自动化项目,以及如何通过自动化工具做到这一点。我们会聊聊充分的项目自动化所带来的好处、项目自动化的类型和特性,以及那些能够让你实现项目自动化的工具。

传统的面向Java项目的构建工具有两个:Ant和Maven。我们会重温它们的主要特性,阅读一些构建代码,谈谈它们的缺点。最后,我们会一起讨论一个满足当代项目自动化需求的构建工具应该提供什么。1.1 没有项目自动化的生活

回到Tom和Joe的困境中,让我们看看为什么项目自动化是一件无须用脑的事情。不管你相信与否,许多开发人员都面临下面这些情况。原因各有不同,但是可能听起来很熟悉。

● IDE给我们做了这些事情。在Acme公司,开发人员在IDE中进行编码,从浏览源代码、实现新的特性、编译、重构,到运行单元测试和集成测试。当有新的代码编写出来时,他们就按一下“编译”按钮。如果IDE告诉他们没有编译错误且测试通过,他们就会把代码提交到版本控制中,这样就可以共享代码了。IDE是一个强大的工具,但是每个开发人员第一次使用时都需要安装一个标准化的版本来执行所有的任务。这是Joe在使用新特性时学到的一课,因为他发现只能使用最新版本的编译器编译。

● 在我的机器上可以跑。眼睛盯着滴答作响的时钟,Joe从版本控制系统中更新代码,却发现根本不能编译。似乎源代码中有一个类丢失了。他问Tom,Tom也奇怪为什么在Joe的机器上不能编译代码。在经过讨论之后,Tom意识到他可能忘记提交某个类文件了,结果导致编译失败。团队的其他人员都由于这个原因而不能继续工作,直到Tom把丢失的文件提交上去。

● 代码的集成完全就是个灾难。Acme公司有两个不同的开发组,其中一个组专注于构建基于Web的用户界面,另一个组工作于服务器后台代码。两个组的人员一起坐在Tom的机器前,运行编译整个应用程序,要构建出一个可交付的软件,然后部署到测试环境中的一个Web服务器上。第一次的欢呼声很快就结束了,因为团队发现某些功能并没有像预期的那样正常工作。某些URL根本不能被解析或者导致错误。虽然团队写了一些功能测试,但却不能定期地在IDE里工作。

● 测试过程慢得像在爬。质量保证(QA)团队渴望立刻拿到应用程序的第一个版本。你能想象到,他们可不想测试低质量的软件。开发团队的每一次修复,他们都不得不手动地走完同样的流程。团队停止向版本控制系统中提交新的代码,一个新的软件版本从IDE中构建出来,并且将可交付软件拷贝到测试服务器上。每一次,一个开发人员都要全身心地投入到这项工作中,而不能给公司带来其他价值。在经过几周测试之后,一个成功的样例程序交付到投资者手中,QA团队说应用程序已经准备好在黄金时间上演一出好戏。

● 部署过程变成了马拉松。从经验上看,团队知道部署一个应用的结果是不可预知的,因为存在不可预知的问题。基础设施和运行时环境必须配置好,数据库需要的种子数据必须要准备好,实际的部署需要被执行,并且需要执行初期的健康监控。当然,团队是有计划的,但是每一步都需要手动执行。

软件发布非常的成功。接下来的一周,CTO在开发人员的桌子前游荡;他已经有了一些新的想法来提高用户体验。一个好朋友告诉他敏捷开发,一种时间控制的迭代式实现和发布软件的方法。他向团队建议两周一次的发布周期。Tom和Joe互相看着对方,两个人都已经被预知的手动和重复工作吓到了。于是,他们俩想到了一起,决定自动化实现和交付软件的每一步,以此来减少构建失败、后期集成和痛苦部署的风险。1.2 项目自动化的好处

这个故事很清楚地说明了项目自动化对于团队的成功是多么的重要。如今,发布时间对于市场变得比以前更重要了。能够以一种可重复、可持续的方式构建和交付软件是关键。让我们看一看项目自动化所带来的好处。1.2.1 防止手动介入

不得不手动地执行每一步去实现和交付软件是耗时且易于犯错的。坦白地说,作为一个开发人员和系统管理员,比起编译过程和拷贝文件,还有更重要的事情要做。我们都是人,难免会犯错,而且手动介入还会占用你真正做实际事情的时间。软件开发过程中的任何一步都是能够且应该被自动化的。1.2.2 创建可重复的构建

软件的构建通常都有预定义和有序的步骤。比如,你需要先编译源代码,然后运行测试,最后组装可交付软件。你将需要每天一遍又一遍地重复运行相同的步骤。这应该和按一下按钮一样简单。无论是谁在运行该构建,构建过程的结果都应该是可重复的。1.2.3 让构建便携

你已经看到,能够在IDE中运行的构建是非常有限的。首先,你必须将特定的产品安装在机器上。其次,IDE也许只适用于某一种操作系统。一个自动化构建不应该依赖于特定的运行环境才能工作,无论是操作系统还是IDE。最佳的方式应该是,自动化任务从命令行运行,它允许你在任何时间和任何一台想要运行构建的机器上运行。1.3 项目自动化的类型

在本章的开始,你看到了用户可以请求一个构建运行。用户可以是任何想要触发该构建的利益相关者,比如开发人员、测试人员或者产品拥有者。例如,我们的好朋友Tom,当他想要编译代码时,就按一下“编译”按钮。按需自动化只是项目自动化的一种类型。你也可以将构建安排在某一个预定义时间触发或者某个特殊事件发生时触发。1.3.1 按需构建

按需构建的典型用例就是用户在自己的机器上触发构建,如图1.1所示。而使用版本控制系统(VCS)来管理构建定义的版本和源代码文件是一种很常见的做法。图1.1 在版本控制系统支持下按需执行构建定义

在大多数情况下,用户在命令行执行一个脚本去运行预先定义的有序任务——比如,编译源代码,拷贝文件从A目录到B目录,或者组装一个可交付软件。通常,这种类型的构建一天要运行多次。1.3.2 触发构建

如果你正在实践敏捷开发,那么你会对一件事情感兴趣,那就是快速得到项目健康程度的反馈。你会想要知道,是否源代码能够无错误地编译,是否有单元测试或集成测试失败,以反馈软件中存在的潜在缺陷。这种类型的自动化通常是在向版本控制系统中提交代码时触发,如图1.2所示。图1.2 构建由一次代码提交触发1.3.3 预定构建

预定构建是一种基于时间的程序调度方案(在UNIX操作系统背景下,也叫作定时作业)。它在特定的间隔时间或者某个具体时间运行——例如,每天的凌晨1:00点,或者每隔15分钟。和所有的定时作业一样,预定的自动化任务通常运行在一个专用的服务器上。图1.3显示的是一个预定的构建在每天凌晨5:00点运行。这种类型的构建特别适用于生成报告或者项目的文件操作。图1.3 计划每天5:00am初始化构建

实现预定义和触发构建的实践方式通常也叫作持续集成(CI)。你会在第13章学到更多关于持续集成的知识。

在认识了项目自动化的好处和类型之后,是时候来讨论一下那些能让你实现这些功能的工具了。1.4 构建工具

当然,你可能会问自己,为什么需要另外一个工具来实现项目自动化。用可执行脚本的方式完全可以写一些逻辑,例如shell脚本。回想一下我们之前讨论过的关于项目自动化的目的。你想要有一个工具,它能够帮助你创建一个可重复的、可靠的、便携的且不需要手动干预的构建。一个shell脚本可不是那么容易就能从UNIX系统迁移到Windows系统上的,所以这样就无法满足你的需求了。1.4.1 什么是构建工具

你所需要的是一个可编程的工具,它能够让你以可执行和有序的任务来表达自动化需求。假设你想要编译源代码,将生成的class文件拷贝到某个目录,然后将该目录组装成可交付的软件。这个可交付的软件可以是一个ZIP文件,比如,它可以被发布到某一个运行时环境中。图1.4展示了所描述场景中的任务和它们执行的顺序。图1.4 一个以预定义顺序执行任务的常见场景

每个任务都代表着一个工作单元——例如,编译源代码。顺序是非常重要的。如果所需要的class文件没有被编译出来,那么你是不能创建ZIP构件的。因此,编译任务必须先被执行。

有向非循环图

本质上,任务和它们的相互依赖被模块化成一个有向非循环图(DAG)。DAG是计算机科学里的一种数据结构,包含下面两个元素。

● 节点:一个工作单元;就构建工具而言,它指的是一个任务(例如,编译源代码)。

● 有向边:有向边也叫作箭头,表示点节之间的关系。在这里,箭头表示依赖关系。如果一个任务的定义依赖于另一个任务,那么所依赖的任务就必须先被执行。发生这种情况常常是因为一个任务依赖于另一个任务的输出。这里有个例子——要执行任务“组装可交付软件”,你需要先执行任务“拷贝class文件到目录”和“编译源代码”。

每个节点都知道自己的执行状态。一个节点——表示一个任务——只能被执行一次。例如,如果两个不同的任务都依赖于任务“编译源代码”,那么你只会想要执行一次这个任务。图1.5以DAG图的形式展示了这种场景。

你也许已经注意到,在图1.4中,节点与任务显示的方向相反。这是因为顺序由节点的依赖决定。作为一个开发人员,你没有必要与DAG图打交道。这个工作是由构建工具来完成的。在本章的后面,你会看到基于Java的构建工具是如何在实践中使用这些概念的。图1.5 有向非循环图表示的任务1.4.2 构建工具的剖析

理解构建工具中组件的交互、构建逻辑的实际定义,以及输入和输出的数据是非常重要的。让我们一起来探讨一下构建工具中每一个元素以及它们的职责。

构建文件

构建文件包含了构建所需的配置信息、定义外部依赖,例如第三方类库,还包含了以任务形式实现某个特殊目的的指令和它们的相互依赖关系。图1.6展示了一个描述4个任务和它们之间相互依赖的构建文件。

在前面场景中我们讨论的任务——编译源代码、拷贝文件到目录以及组装ZIP文件——都可以定义在构建文件中。在通常情况下,会使用脚本语言来表达构建逻辑。这就是为什么一个构建文件也叫作构建脚本的原因。图1.6 构建文件说明的构建规则由任务以及它们之间的依赖表示

构建的输入和输出

一个任务会接收一个输入,然后执行一系列步骤,最后产生一个输出。某些任务也许不需要输入,也不需要产生一个必要的输出。在复杂的任务依赖关系中,也许会使用一个依赖任务的输出作为输入。图1.7展示了在任务关系图中输入的消耗和输出的产生。图1.7 任务的输入和输出

下面我给出的例子遵循这个流程。我们将源代码文件作为输入,将它们编译为class文件,并组装成可交付软件作为输出。编译和组装过程各表示一个任务。只有先编译了源代码,组装可交付软件才有意义。因此,两个任务需要保证它们的顺序。

构建引擎

构建文件的一步步指令或者规则集必须被翻译成构建工具可以理解的内部模型。构建引擎会在运行时处理构建文件,解析任务之间的依赖,设置好执行所需要的全部配置,如图1.8所示。图1.8 构建引擎将规则集翻译成内部模型表现方式,并在构建运行时被访问

一旦内部模型建立好了,引擎就会按照正确的顺序去执行一系列任务。某些构建工具还允许你通过API去访问这个模型,以便在运行时获取构建信息。

依赖管理器

依赖管理器用于处理你在build文件中声明的依赖定义,从工件仓库(例如,本地文件系统、一个FTP或者HTTP服务器)中解析它们,并使它们对项目可用。依赖通常是指外部依赖,一种JAR文件形式的可重用类库(例如,Log4j对日志的支持)。该仓库就像是依赖的储藏所,通过标识符组织和描述它们,例如名字和版本。一个典型的仓库可以是HTTP服务器或者本地文件系统。图1.9展示了依赖管理器在构建工具架构中所处的地位。图1.9 构建可以访问依赖管理器获取外部依赖

许多类库还依赖于其他类库,这叫作传递依赖。依赖管理器可以通过存储在仓库中的元信息自动地解析传递依赖。但是一个构建工具并不要求提供这样的依赖管理组件。1.5 Java构建工具

在本节,我们会看到两个流行的基于Java的构建工具:Ant和Maven。我们会讨论它们的特性,看看实际的样例脚本,并概述每个工具的缺点。我们首先来看最早的工具——Ant。1.5.1 Apache Ant

Apache Ant (Another Neat Tool)是一个用Java编写的开源构建工具。其主要目的是在Java项目中为常用任务提供自动化,例如编译源代码、运行单元测试、打包JAR文件和生成Javadoc文档。另外,它还为文件系统和存档操作提供了许多不同的预定义任务。如果任何一个任务不满足需求,那么你就可以用Java写新的任务来扩展构建。

虽然Ant的核心是用Java编写的,但是build文件是通过XML表示的,这样就可以在任何运行时环境下使用了。Ant不提供依赖管理器,所以你需要自己管理外部依赖。然而,Ant可以和另一个Apache项目Ivy很好地集成,它是一个完善且独立的依赖管理器。要集成Ant和Ivy需要一些额外的工作,而且要为每个独立的项目手动配置。让我们一起看一个样例构建脚本。

构建脚本术语

要理解Ant的构建脚本,你需要先了解一些命名规范。一个构建脚本由三个基本元素组成:一个project、多个target和可用的task。图1.10展示了每个元素之间的关系。图1.10 Ant的构建脚本层级结构:project、target、task

在Ant中,task是一段可执行的代码——例如,创建一个目录或者移动一个文件。在构建脚本中,通过预定义的XML标签名来使用一个task。task的行为可以由其暴露出来的属性配置。下面的代码片段展示了如何在构建脚本中调用javac的task来编译Java代码:

Ant自身带有许多预定义的task,然而你也可以用Java语言编写自己的task以扩展脚本功能。

target是你想要执行的task的一个集合,可以把它想成一个逻辑组。当在命令行中运行Ant时,提供了你想要运行的target的名字。通过声明target之间的依赖关系,就可以创建一个完整的命令链。下面的代码片段展示了两个依赖的target:

project是对于所有Ant项目都必要的容器。它是Ant脚本的顶级元素,包含一个或多个target。在每个构建脚本中,你只能定义一个project。下面的代码片段展示了project和target的关系:

有了对Ant层级结构的基本理解,让我们来看一个完整场景的构建脚本样例。

构建脚本样例

假设你想要写这样一个脚本,用Java编译器去编译src目录下的Java源代码,并将结果放在输出目录build中。Java源代码中有一个类依赖于Apache Commons Lang类库。将类库中的JAR文件放置在classpath路径下,这样编译器就知道该类库的存在了。在编译完成之后,你想要组装一个JAR文件。对于每一个工作单元,源代码编译和JAR文件的组装都会被分配到一个独立的target中。你还需要添加另外两个target去做初始化和对输出目录进行清理。图1.11展示了该Ant构建脚本的结构。图1.11 Ant构建脚本样例的项目层级结构

让我们深入到业务中,是时候用Ant构建脚本去实现这个例子了。下面的清单展示了整个项目,以及实现该目标所需要的target。

清单 1.1 含有编译源代码和组装JAR文件任务的Ant脚本

Ant没有对如何定义构建的结构强加任何限制。这样让适应一个现有的项目结构变得简单。例如,在样例脚本中,源代码目录和输出目录是随意选择的。通过修改相关的属性可以非常轻松地改变它们。对于target的定义也是一样的;对于每个target,哪个逻辑需要被执行,以及它们的执行顺序,你拥有完全灵活的选择性。

缺点

尽管有这样的灵活性,但是你也应该注意到一些缺点:

● 使用XML作为构建逻辑的定义语言相比于其他更简明的定义语言,会导致构建脚本过于臃肿和啰唆。

● 复杂的构建逻辑会导致又长又难以维护的构建脚本。当尝试用标记语言去定义类似if-then/if-then-else的逻辑语句时,它完全就成了一种负担。

● Ant没有提供任何指导来告诉你如何建设项目。在一个企业级配置中,这常常会导致一个build文件每一次看上去都不一样。常用功能时常被到处拷贝。项目中每一个新的开发人员都需要去理解构建中每一个独立的部分。

● 你想要知道在构建中有多少个类被编译或者多少个task被执行。Ant没有暴露任何的API能够让你在运行时获取内存模型中的信息。

● 在没有Ivy的情况下,使用Ant很难管理依赖。在通常情况下,你需要将JAR文件提交到版本控制系统中,并且手动管理组织结构。1.5.2 Apache Maven

在企业应用的多个项目中使用Ant,对可维护性有很大的影响。灵活性带来了许多由项目间拷贝产生的重复代码。Maven团队认识到标准化项目布局和统一构建生命周期的必要性。Maven选择约定优于配置的思想,这意味着它为你的项目配置和行为提供了有意义的默认值。项目自然而然就知道去哪些目录寻找源代码以及构建运行时有哪些task去执行。如果你的项目遵从默认值,那么只需要写几行XML就可以建立一个完整的项目。另外,Maven也拥有为应用产生包含Javadoc在内的HTML格式项目文档的能力。

Maven的核心功能可以通过开发定制的插件来扩展。Maven的社区非常活跃,几乎支持构建的每个方面,从集成其他工具到生成报告,你都能够找到合适的插件。如果找不到满足需求的插件,你也可以自己去写。

标准的目录布局

通过引入一个默认的项目布局,Maven确保每个拥有Maven知识的开发人员可以立刻知道去哪里找什么类型的文件。例如,Java应用程序源代码的目录是src/main/java。所有默认的目录都是可配置的。图1.12展示了一个Maven项目的默认布局。图1.12 Maven的默认项目布局定义了Java源代码、资源文件和测试代码的位置

构建生命周期

Maven基于构建生命周期的思想。每个项目都确切知道有哪些步骤去执行构建、打包和发布应用程序,包括如下功能:

● 编译源代码

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

● 组装工件(例如,JAR文件)

● 将工件部署到本地仓库

● 将工件发布到远程仓库

在构建生命周期中每个步骤都称作一个阶段(phase)。这些阶段会被有序地执行。当在命令行中运行构建时,你想要执行的阶段是固定的。假设你调用打包这个阶段,Maven会自动确定它所依赖的阶段如编译源代码和运行测试事先被执行。图1.13展示了Maven构建所预定义的阶段和它们执行的顺序。图1.13 Maven最重要的构建生命周期阶段

依赖管理

在Maven项目中,所需要的外部依赖库都在构建脚本中定义。例如,如果项目需要Hibernate,那么你可以在依赖配置块中简单地定义它的独立工件坐标,比如组织名、工件名和版本。下面的代码片段展示了如何声明一个4.1.7 Finial版本的Hibernate核心库:

在运行时,声明的类库和它们的传递依赖会由Maven的依赖管理器下载,保存到本地缓存中,这样你的构建就可以使用它们(例如,编译源代码)。Maven预配置从Maven Central下载依赖。接下来构建会从本地缓存中重用已存在的工件,因此不用再连接Maven Central。Maven Central是Java社区中最流行的二进制工件仓库。图1.14展示了Maven工件的获取过程。图1.14 通过与Maven Central的交互为构建解析和下载依赖

Maven中的依赖管理不仅限于外部库。你也可以将其他Maven项目定义为依赖。这种需求出现的原因是软件分解成了多个模块,每个模块都是完成某项功能的组件。图1.15展示了一种传统的三层结构的模块化架构。在这个例子中,表现层包含了在页面渲染数据的代码,业务层是真实的业务对象,而集成层则从集成库中获取数据。图1.15 软件项目的模块化架构

构建脚本样例

下面的清单展示了一个Maven构建脚本样例,名字是pom.xm,它实现了和Ant构建脚本相同的功能。记住,在这里要遵循默认约定,所以Maven会去src/main/java目录中寻找源代码,而不是src。

清单 1.2 构建标准Java项目的Maven POM文件

缺点

和Ant一样,也要知道Maven的缺点:

● Maven推荐一个默认的结构和生命周期,常常会太过限制,也许不适合你的项目需求。

● 为Maven写定制的扩展过于累赘。你需要去学习Mojos(Maven的内部扩展API),如何提供一个插件描述符(又是XML),以及相关的特殊注解,以便提供扩展实现所需要的数据。

● Maven的早期版本(低于2.0.9)会自动尝试更新它们自己的核心插件,例如,将单元测试的支持插件升级到最新版本。这可能会导致脆弱和不稳定的构建。1.5.3 对下一代构建工具的需求

在上面小节中,我们了解了Ant和Maven工具的特性,以及它们的优势和缺点。很明显,你常常需要在选择构建工具时妥协于它们所支持的功能。要么你选择完全灵活且可扩展,但很难实现项目标准化,有一堆公式化代码,并且没有依赖管理支持的Ant,要么选择Maven,它能提供约定优于配置的方式和无缝的依赖管理器集成,但过于限制思维和拥有臃肿的插件系统。

如果一个构建工具能够折中,是不是很棒?下面的一些特性是一个演变的构建工具应该提供的:

● 具有表达性、声明式、可维护的构建语言。

● 标准化的项目布局和生命周期,但是具有完全的灵活性和对默认值的完全可配置性。

● 拥有易用且灵活的方式去实现定制逻辑。

● 支持构建由多个项目组成的项目结构。

● 支持依赖管理。

● 能很好地集成和迁移现有的构建基础设施,包括能够引入现有的Ant构建脚本和可以将现有的Ant或Maven逻辑转换成其自身规则集的工具。

● 强调可扩展性和高效率的构建。如果你的项目需要长时间构建(比如2小时或更长时间),这一点是很重要的,某些大型的企业级项目就是这样。

本书会向你介绍一个工具,它提供了这些很棒的特性,它的名字叫作Gradle。我们会一起学习如何使用Gradle和探索它能提供的所有优点。1.6 总结

对于开发和测试人员来说,没有项目自动化的工作,都是重复、单调和易犯错的。伴随软件交付过程中的每一步——从源代码编译到打包软件,再到发布至测试和产品环境——都必须手动操作。项目自动化帮你消除手动操作介入的负担,让你的团队更有效率,带你进入到一个一键式和故障安全的软件发布过程。

在本章,我们了解了不同类型的项目自动化——按需构建,预定构建和触发构建——覆盖了各种特殊用例。你应该了解到不同类型的项目自动化是不相互排斥的。实际上,它们是互相补充的。

项目构建工具是项目自动化的一个关键因素。它允许你声明一系列有序的规则,允许你在初始化构建时执行。通过分析构建工具的内部原理,我们讨论了构建工具的活动组件。构建引擎(构建工具的可执行度)处理构建脚本中预定义的规则集,并将它翻译成为可执行的任务。每个任务也许需要输入数据。最终,产生构建的输出。依赖管理器是构建工具架构中的一个可选组件,它允许你声明项目正常运行时所需要的外部库。

通过深入了解两个流行的Java构建工具:Ant和Maven的实现方式,我们看到了构建工具的具体特性。Ant提供了一种非常灵活且通用的方式来定义构建逻辑,但是没有对标准化项目提供指导或者有意义的默认任务,以便可以在项目中重复使用。它也没有提供一个开箱即用的依赖管理器,需要自己去管理外部依赖。Maven,则正好相反,它遵循约定优于配置的原则,支持有意义的默认配置和标准的构建生命周期。Maven的内置特性支持对外部库和直接对Maven项目的自动化依赖管理。但Maven的败笔却落在定制逻辑和非约定项目的结构和任务的易扩展性上。你知道,一个高级的构建工具需要在灵活性和可配置约定上折中,这样才能满足现代化软件项目的需求。

在下一章中,我们会来了解Gradle是如何满足构建需求的。2 下一代构建工具:Gradle

本章涵盖

■ 理解Gradle和其他构建工具的不同

■ 介绍Gradle的引人注目的特性集

■ 安装Gradle

■ 编写和执行简单的Gradle脚本

■ 在命令行中运行Gradle

多年来,构建只有编译和打包的简单需求。但是现代软件开发的规模改变了,因此有了对自动化构建的需求。

今天,大多数项目都包含有多而杂的技术栈、混合的多种编程语言,并且使用多种测试策略。随着敏捷实践的崛起,构建不得不更早地支持代码集成,以及频繁和简单地交付软件到测试和产品环境。

现有的构建工具不能够以一种简单但是可定制的方式去满足这些要求。多少次你注视着XML文件,只是想要弄清楚构建是怎么工作的?而且为什么不能以更简单的方式向构建中添加定制逻辑?通常,当你向一个构建脚本中添加逻辑时,总摆脱不了一种使用了变通方式或者非常规方式实现的感觉。我深知你的痛苦。一定有一种更好的方式,即以一种可表达且可维护的方式去做这些事情。确实有这样的方式,那就是Gradle。

Gradle是基于JVM构建工具的新一代版本。它从现有的构建工具如Ant和Maven中学到了很多东西,并且把它们的最优思想提升到更高层次。遵循基于约定的构建方式,Gradle可以用一种声明式的方式为你的问题领域建模,它使用一种强大的且具有表达性的基于Groovy的领域特定语言(DSL),而不是XML。因为Gradle是基于JVM的,它允许你使用自己最喜欢的Java或者Groovy语言来编写定制逻辑。

在Java世界里,有大量类库和框架可以使用。依赖管理可以自动地从仓库中下载工件,并为项目代码所用。Gradle从现有的依赖管理解决方案的缺点中学习,提供了一套自己的依赖管理实现方式。不仅高度可配置,而且也尽可能地与现有的依赖管理设施(如Maven和Ivy)相兼容。Gradle管理依赖的能力不仅限于外部库。随着项目大小和复杂度的增加,你会想要以模块的方式来组织代码,以清晰地定义它们的职责。Gradle对多项目构建的定义和组织提供了强有力的支持,以及对项目之间的依赖建模。

我知道,所有这些听起来都让你感觉看到了希望,但是你当前还陷在遗留的构建当中。Gradle不会把你留在烂摊子里面,它会让你的迁移变得简单。Ant可以在运行时装载,因此不需要任何额外的设置。Gradle允许团队利用他们已经累积的Ant知识,以及在已有构建基础设施中的投入。想象一下,在Gradle构建脚本中直接使用已经存在的Ant任务和脚本的可能性。遗留的构建逻辑能够被重用或者逐渐迁移。Gradle的确减轻了你不少的负担。

要开始使用Gradle,你所需要的就是对Java编程语言有一个较好的理解。如果你是第一次接触项目自动化或者以前没有使用过构建工具,那么阅读第1章是一个好的开始。本书会告诉你如何有效地使用Gradle进行构建和交付真实世界的项目。

在本章中,我们会将Gradle提供的特性和现有的基于JVM语言的构建工具进行对比。之后,你会了解到Gradle是如何在持续交付的部署管道中帮助你实现自动化软件交付的。要初次体验使用Gradle的感觉,你需要首先安装Gradle,然后编写一个简单的构建脚本,并在命令行中运行它。现在,跟我一起去探索振奋人心的Gradle世界吧。2.1 为什么要用Gradle,为什么是现在

如果你曾经与构建系统打过交道,那么当你想到曾经遇到过的挑战时,沮丧也许是其中一种感觉。难道构建工具不应该很自然地帮助你完成项目自动化的目标吗?相反,你不得不向可维护性、可用性、灵活性、可扩展性或者性能妥协。

假设当前的情况是你在给项目构建一个发布版本,而你想要拷贝一个文件到特定的位置。为了确定版本,你需要在描述项目的元数据中检查一个字符串。如果它匹配某种数字模式(例如,1.0-RELEASE),你就将文件从A点拷贝到B点。从局外人的观点看,这也许听起来像是一件不太重要的事情。如果你不得不依赖于XML,许多传统构建工具的构建语言,那么用它来表达逻辑就变成噩梦。构建工具给出的答案是通过非标准扩展机制来添加脚本功能。最终变成将脚本代码与XML混合或者从构建逻辑中触发外部脚本。可以想象,你将会需要越来越多的定制代码。结果就是,你不可避免地引入了偶然的复杂性,而降低了构建的可维护性。难道不应该一开始就使用一种具有可表达性的语言来定义构建逻辑吗?

再举一个例子。Maven遵循约定优于配置的规范,为Java项目引入了一个标准化的项目布局和构建生命周期。如果你想要确保一个待开发的项目——一个对之前的工作没有任何限制的项目,具有统一的项目结构,那么这是一个非常棒的方式。然而,你也许比较幸运,需要在许多遵循不同约定的遗留项目上工作。Maven严格遵循的约定之一就是一个项目需要生成一个工件,比如JAR文件。但是你如何在不改变项目结构的情况下,从一个项目源中生成两个不同的JAR文件呢?仅仅为了这个目的,你就不得不创建两个分开的项目。而且,即使你大费周折地这么做了,也无法改变构建过程需要适应工具,而不是工具去适应构建过程的事实。

也许在现有的解决方案中,你只遇到一部分问题。通常,你需要牺牲非功能性的需求来为企业级自动化领域建模。但是,还是别忍受这些缺点了——让我们看看Gradle是如何解决这些问题的。2.1.1 Java构建工具的演变

让我们看看这些年构建工具是如何演变的。正如第1章所讨论的,有两个工具统领着Java项目的构建:Ant和Maven。经过这么多年,这两个工具都有大步提高和扩展的特性集。虽然它们都非常流行而且变成行业标准,但是却有一个弱点:构建逻辑必须用XML描述。XML是非常好的层级数据描述语言,但是对于描述程序流程和构建逻辑却存在不足之处。随着构建脚本复杂度的增加,维护构建代码就成为了噩梦。

Ant的第一个正式版本是在2000年发布的。每一个工作元素(在Ant的术语中叫target)可以被组合和重用。多个target可以被链接,将单个的工作单元组合成一个完整的工作流。例如,你也许有一个target是Java源代码编译,另外一个target是将class文件打包创建JAR文件。构建一个JAR文件只有在完成代码编译之后才有意义。在Ant中,你让打包JAR的target依赖于编译的target。Ant在如何组织项目结构方面没有给出任何指导。虽然它拥有最大程度的灵活性,但是Ant使得每个构建脚本都是唯一的而且很难理解。项目中需要的外部库通常要提交到版本控制系统中,因为没有高级的机制可以自动地将它们从一个中心位置下载下来。早期的Ant版本需要很多的准则以避免重复代码。它的扩展机制很弱。结果就是,复制和粘贴,这样很差的编码实践成为了唯一的选择。为了统一项目布局,企业需要强制推行一些标准。

Maven 1发布于2004年7月,它尝试去简化这个过程。它提供了一个标准化的项目和目录结构,以及依赖管理。遗憾的是,定制逻辑太难实现了。如果你想要打破Maven的约定,则需要写插件,叫作Mojo,这通常是唯一的解决方案。Mojo这个名字暗示了这是一种直接、简单和迷人的方式来扩展Maven。但事实上,在Maven中写插件是累赘和非常复杂的。

后来,Ant通过Apache的类库Ivy引入了依赖管理来追赶Maven的脚步,它可以完全和Ant集成,声明式地指定项目编译和打包过程中所需要的依赖。Maven的依赖管理器,和Ivy一样,支持解析传递依赖。当我谈到传递依赖时,指的是你指定的依赖自身所需要的类库。一个典型的传递依赖的例子是,XML解析库Xerces需要XML API库才能正常工作。Maven 2发布于2005年10月,它让约定优于配置的思想更进一步。由多个模块组成的项目可以将模块定义成相互的依赖。

这段时间有很多人在寻找现有构建工具的替代品。我们看到了从使用XML到更具表达性和可读性构建语言的转移。Gant是带有这种思想的构建工具,它是在Ant的基础上用Groovy写的DSL。使用Gant,用户可以将Groovy语言的特性与现有的Ant知识结合而不需要写任何XML。即使它不是Maven核心项目的一部分,项目Maven Polyglot也提出了相似的方法,允许你写自己构建定义逻辑,该逻辑使用Groovy、Ruby、Scala或者Clojure语言编写在项目对象模型(POM)文件中。

我们正处在应用开发新纪元的开端:多语言编程。今天许多应用都使用了多种编程语言,每一种语言都最适合实现一个特定的问题领域。很常见的一种情况是,使用客户端语言比如JavaScript与混合的多种后端语言如Java、Groovy和Scala进行通信,而这些后端语言进而会调用由C++编写的遗留系统。最重要的是使用正确的工具做正确的事情。尽管结合多种编程语言有很多好处,但是你的构建工具也需要流畅地支持基础设施。JavaScript需要被合并、最小化和压缩,而你的服务器端和遗留代码则需要被编译、打包和部署。

Gradle恰好符合这一代的构建工具,满足现代构建工具的许多需求(图2.1)。它提供了具有表达性的DSL、约定优于配置的方法和强大的依赖管理。它摒弃了XML,引入了动态语言Groovy来定义构建逻辑。听起来很不错,不是吗?请继续阅读和学习Gradle的特性集,以及如何让你的老板买账。图2.1 Gradle结合了其他构建工具的最佳特性2.1.2 为什么应该选择Gradle

如果你是一个开发者,那么自动化项目就是你日常开发的一部分。难道你就不想把构建代码看作和其他软件代码一样,让它能够被扩展、测试和维护吗?让我们把软件工程搬回到构建中。Gradle构建脚本是声明式的、可读的,并且清晰地表达它们的意图。用Groovy而不是XML写代码,挥洒着Gradle基于约定构建的哲理,大大地降低构建脚本的大小而且更易读(见图2.2)。

看到用Gradle实现相同的目标所需要编写的代码时确实让人感到惊讶。使用Gradle时,你不需要做出妥协。而像Maven这样的构建工具提出的项目布局就是“要么我的方式,要么复杂的方式”,Gradle的DSL提供了灵活性去适应非约定项目布局。

Gradle的座右铭“让不可能成为可能,让可能变得简单,让简单变得优雅”(适当引用Moshé Feldenkrais)。

不要改变一个正在运行的系统,你说呢?你的团队已经花费大量的时间来建立项目构建代码基础设施。Gradle并不强迫你完全迁移所有的构建逻辑。它和其他构建工具如Ant和Maven有非常好的集成,这是Gradle优先级列表中的最高优先级。在第9章,我们会深入了解Gradle的集成特性和可能的迁移策略。

市场似乎注意到了Gradle。在Spring 2010会议上,Gradle因为最具创新性开源项目被授予Springy大奖(http://www.springsource.org/node/2871)。ThoughtWorks,一个声誉很好的软件开发咨询公司,会周期性地发布关于新技术、语言和工具的报告——他们称作技术雷达。技术雷达的目的是帮助软件行业的决策者理解发展趋势和他们对市场的影响。在2013年5月出版的最新报告中(http://thoughtworks.fileburst.com/assets/technology-radar-may-2013.pdf),Gradle被标记为采纳状态,说明这项技术应该被行业所采纳。图2.2 对比Maven和Gradle构建脚本的大小和可读性

被ThoughtWorks承认“有两件事情会让你感到与类似于Ant和Maven这样基于XML的构建工具工作时觉得疲劳:太多的尖括号和粗糙的插件架构。虽然语法问题可以通过升级换代来解决,但随着项目变得越来越复杂,插件架构严重地限制了构建工具的优雅成长。我们感觉插件是一种错误的抽象级别,而更喜欢像Gradle和Rake那样基于语言的构建工具,因为它们提供了更细粒度的抽象和更长期的灵活性。”

Gradle很早就有采纳者了,甚至在1.0版本发布之前。像Groovy和Hibernate这样流行的开源项目已经完全切换到Gradle并作为它们构建的支柱。每一个Android项目都使用Gradle作为默认的构建系统。Gradle给商业市场也带来了影响。像Orbitz、EADS和Software AG这样的公司也使用Gradle,这里只列出了几个公司。VMware,作为Spring和Grails背后的公司,对选择Gradle做出了巨大的投资。他们的许多软件产品,比如Spring框架和Grails,都是建立在对Gradle能够完成交付的信任上的。2.2 Gradle引人注目的特性集

让我们进一步看看Gradle那些与竞争对手不同的特性集:引人注目的特性集(见图2.3)。总结起来,Gradle是一个为企业准备的构建系统,由具有声明式和表达性的Groovy的DSL支持。它结合了灵活性和基于约定优于配置思想的扩展性,以及对传统依赖管理的支持。它背后有一个专业的服务公司(Gradleware)和强大的社区参与,Gradle成为了许多开源项目和企业构建方案的第一选择。图2.3 Gradle引人注目的特性集2.2.1 可表达性的构建语言和底层的API

在构建脚本中解锁Gradle强大特性的关键需要你去探索和应用它的领域模型,如图2.4所示。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载