Martin的《持续集成》
相信很多读者和我一样,最早接触到持续集成的概念是来自Martin的著名文章《持续集成》,该文最早发布于2000年9月,之后在2006年进行了一次修订,它清晰地解释了持续集成的概念,并总结了10条实践,它们分别为:
-
只维护一个源码仓库
-
自动化构建
-
让构建自行测试
-
每人每天向主干提交代码
-
每次提交都应在持续集成机器上构建主干
-
保持快速的构建
-
在模拟生产环境中测试
-
让每个人都能轻易获得最新的可执行文件
-
每个人都能看到进度
-
自动化部署
原始文章距今已10年有余,这在软件行业中算是很长的时间了,但我们都能看到Martin总结的这些实践依旧闪耀着光芒,依旧有很多团队在努力实践它们并得到了丰厚的回报,当然也有很多团队因为各种原因拒绝实践持续集成从而无法体会到个中好处。
从这10条实践中我们能找到很多流行开源工具的影子,例如版本控制工具cvs、svn、git,自动化构建工具Maven、Ant,自动化测试框架JUnit、TestNG,以及持续集成服务器CruiseControl和Hudson等等。其实不论你是否实践持续集成,单独使用这其中的很多工具都能发挥极大的价值,持续集成的一大意义在于它引入了一个有效的流程,能让这些工具有机融合,并相互促进。 关于持续集成还有一本获得Jolt大奖的图书,名为《持续集成——软件质量改进和风险降低之道》。但无论是Martin的文章,还是这本图书,都没有阐述使用Maven作为自动化构建工具实施持续集成的细节。本文旨在介绍一些基于Maven实施持续集成的实践,希望这些经验能从具体处帮助到读者。
架设私有Maven仓库
Martin的文章并没有涉及到依赖管理的内容,但在Java的世界中,依赖管理是开发人员不得不面对的问题。无论是外部的开源类库依赖,还是项目内部的模块间依赖,都需要有效地管理。可以说依赖管理是持续集成核心的内容之一。Maven通过其依赖管理机制和随处可用的中央仓库有效地解决了这个问题,用户只需要在POM中声明项目所需要的依赖,Maven就能在构建的时候自动从仓库解析依赖。
不过仅仅这样是不够的,我们知道,持续集成的最大好处在于降低风险,简单地来说就是尽早暴露问题,能让开发人员及早发现并修复,从而降低修复成本。可是,如果每个人都从中央仓库重复下载依赖,这是非常耗时的,集成的反馈周期肯定会延长。我已经无数次听到有人抱怨“Maven在下载整个Internet!”。构建要快!持续集成反馈要快!Maven你不能拖慢这个流程。
幸运的是开源世界有很好的解决方案,只要使用Maven仓库管理器软件如Nexus建立一个私有的Maven仓库,问题就能迎刃而解。原理很简单,这个位于局域网内的Maven仓库能够代理所有外部仓库,从而避免所有人从Internet重复下载依赖文件。这样Maven解析依赖的时候仅限于局域网,构建速度就大大地加快了。例如大家都需要使用junit-4.8.2.jar
,当第一个人向私有仓库请求的时候,私有仓库从中央库下载并缓存下来,假设耗时10s,之后其他人需要junit-4.8.2.jar
的时候,私有仓库直接使用缓存的文件,这个耗时可能就是1s。如果有100个开发人员使用该文件,那节省的时间就是 100 * 10 - ( 10 + 99 * 1 ) = 891s ,实际情况中依赖的数量可能会是成百上千,那节省的时间就变得非常的可观。
也许有人会说,我也完全可以将项目依赖加入到版本控制中,这一点甚至在《卓有成效的程序员》中都被明确提及,在该书第5章的"DRY版本控制"一节中,Neal Ford有这么一段话:“所有用来构建项目的东西都应该被放入版本控制,包括二进制文件(类库,框架,JAR文件,构建脚本等等)”。作者进一步解释了其目的,这么做能够保证项目不受外部因素影响(如依赖版本变化,甚至丢失),保证构建的稳定,作者也同时提及了一般版本控制工具处理二进制文件的性能问题。抛开这条结论性的实践,仔细考虑其目的,我们就能发现,私有Maven仓库同样能保证构建的稳定,而且能避免版本控制工具处理二进制文件而造成的潜在性能问题。所以,我斗胆说一句,Neal Ford所提的这条实践OUT了!
私有Maven的仓库的意义还不仅限于此,结合自动化部署和Maven的SNAPSHOT机制,它能大大促进项目集成的效率。
在模块化的开发环境中,大家各司其职,专注于自己所负责的模块,持续集成的规则是,在往版本控制提交代码前,需要先保证本地构建没有问题,那一般的做法就是更新所有模块的代码并构建。可是,真的需要构建那些其实你并不怎么关心的模块么?且不谈一旦构建他人代码时出错,你往往会不知所措,这种做法同时也增加了本地构建的时间。
Maven有SNAPSHOT版本的概念,其目的就是让你能够构建一个临时的版本,供团队他人使用,这样他们就不必在代码的层次关心自己的依赖。于是私有Maven仓库就充当了一个中介的作用,而持续集成服务器就多了一个职责,每次它成功构建一个模块,都应该将该模块的SNAPSHOT版本发布到Maven仓库中。现在,大家就不用去构建别人的代码了,Maven能自动帮你从私有仓库解析下载依赖的最新SNAPSHOT(使用mvn命令的-U参数强制更新)。注意,除了持续集成服务器外,任何其他人都不应该发布SNAPSHOT版本到Maven仓库,因为只有持续集成服务器的环境是可信任的,你能在本地成功执行mvn clean install并不代表持续集成服务器上该命令能成功,由于每个人的本地环境各有差异,因此集成的成功与否应当以持续集成服务器为准,而只有集成成功后,SNAPSHOT才可以被部署到私有仓库供他人使用。
鉴于上述的原因分析,我认为在基于Maven的持续集成环境中,再怎么强调私有Maven仓库的重要性都是不为过的。
正确的集成命令
在持续集成服务器上使用怎样的 mvn 命令集成项目,这个问题乍一看答案很显然,不就是 mvn clean install 么?事实上比较好的集成命令会稍微复杂些,下面是一些总结:
-
不要忘了clean: clean能够保证上一次构建的输出不会影响到本次构建。
-
使用deploy而不是install: 构建的SNAPSHOT输出应当被自动部署到私有Maven仓库供他人使用,这一点在前面已经详细论述。
-
使用-U参数: 该参数能强制让Maven检查所有SNAPSHOT依赖更新,确保集成基于最新的状态,如果没有该参数,Maven默认以天为单位检查更新,而持续集成的频率应该比这高很多。
-
使用-e参数:如果构建出现异常,该参数能让Maven打印完整的stack trace,以方便分析错误原因。
-
使用-Dmaven.repo.local参数:如果持续集成服务器有很多任务,每个任务都会使用本地仓库,下载依赖至本地仓库,为了避免这种多线程使用本地仓库可能会引起的冲突,可以使用-Dmaven.repo.local=/home/juven/ci/foo-repo/这样的参数为每个任务分配本地仓库。
-
使用-B参数:该参数表示让Maven使用批处理模式构建项目,能够避免一些需要人工参与交互而造成的挂起状态。
综上,持续集成服务器上的集成命令应该为 mvn clean deploy -B -e -U -Dmaven.repo.local=xxx 。此外,定期清理持续集成服务器的本地Maven仓库也是个很好的习惯,这样可以避免浪费磁盘资源,几乎所有的持续集成服务器软件都支持本地的脚本任务,你可以写一行简单的shell或bat脚本,然后配置以天为单位自动清理仓库。需要注意的是,这么做的前提是你有私有Maven仓库,否则每次都从Internet下载所有依赖会是一场噩梦。
用好Profile
如果不需要考虑各种不同的环境, 而且你的自动测试(包括集成测试)跑得飞快,那你就不用为项目建立多个集成任务。但实际的情况是,集成的时候可能要考虑各种环境,例如开发环境、测试环境、产品环境。而当项目越来越大,测试越来越多,控制构建时间在一个可接受的范围内(例如10分钟)变得越来越不现实。《持续集成——软件质量改进和风险降低之道》中介绍了一种名为分阶段构建(staged build)的解决方案,例如你可以将构建分为两个部分,第一部分包括了编译和单元测试等能够快速结束的任务,第二个部分包括集成测试等耗时较长的任务,只有第一部分成功完成后,才触发第二部分集成。这么做的意义在于让持续集成的反馈尽可能的快。
Maven的Profile机制能够很好的支持分阶段构建。例如,借助Maven Surefire Plugin,你可以统一单元测试命名为**UT
,统一集成测试命名为**IT
,然后配置Maven Surefire Plugin默认只运行单元测试,然后再编写一个名为integrationTest的Profile,在其中配置Maven Surefire Plugin运行集成测试。然后再以此为基础分阶段构建项目,第一个构建为 mvn clean install -B -e -U ,第二个构建任务为 mvn clean deploy -B -e -U -PintegrationTest 。前一个构建成功后再触发第二个构建,然后才部署至Maven仓库。值得一提的是,Maven Surefire Plugin能够很好支持JUnit 3、JUnit 4和TestNG,你可以按照最适合自己的方式来划分单元测试和集成测试。
另一个常见的分阶段构建案例是生成Maven站点,使用 mvn clean site 生成站点往往比较耗时且耗资源,这样的任务对应的持续集成中的持续审查阶段,该阶段往往不需要很高的集成频率。你会希望每10分钟就检查源代码变更并编译测试,但很少有人会希望每10分钟让系统生成一次测试覆盖率报告、CheckStyle报告等内容,因此合理的做法是使用一个较低的频率,例如每天,这样可以避免无谓的资源消耗,更重要的是,这样不会拖慢本该很快的编译和单元测试等反馈内容。
还有一些情况是系统需要基于不同环境进行集成,这时候就需要用到Maven的属性机制、资源过滤、以及前面提到的Profile。篇幅原因,这里不再展开。
小结
持续集成是敏捷最重要的实践之一,但如何在基于Maven的环境下实践持续集成却鲜有文章详述,本文介绍了一些该主题的最佳实践,包括架设私有仓库、使用正确的集成命令、利用Profile等技术处理分阶段构建等等。本文旨在让广大Maven用户认识到这些实践的存在及重要性,并没有详细解释一些诸如Nexus安装配置、Maven Surefire Plugin配置、或者说Profile配置使用方面的细节,如果你希望看到更细节的介绍,可以参考我的《Maven实战》一书。除了上面的内容之外,该书还详细解释了如何使用Hudson(也许该改称Jenkins了)这一最流行的开源持续集成服务器。当然,如果你有关于Maven和持续集成方面的经验,也请不吝分享。
相关推荐
**Maven实战——许晓斌完整版** Maven是一个强大的项目管理和构建工具,广泛应用于Java开发领域。由Apache Software Foundation维护,它简化了构建过程,通过一个统一的配置方式管理项目的构建、报告和依赖关系。...
- **Maven实战——入门篇**:这本书的入门部分,引导读者快速上手Maven,理解基本概念和操作。 - **MAVEN使用最佳实践.doc**:可能包含更具体的项目构建、部署和团队协作的最佳实践指导。 以上只是对Maven基础...
《Maven实战》是国内第一本公开出版的Maven专著。它内容新颖,基于最新发布的Maven 3.0,不仅详尽讲解了Maven 3.0的所有新功能和新特性,而且还将这些新功能和新特性与Maven 2.x版本进行了对比,以便于正在使用...
**Maven实战——深入理解与应用** Maven是一款强大的Java项目管理工具,它通过XML格式的配置文件,统一管理项目的构建、报告以及依赖关系。在本文中,我们将深入探讨Maven实战中的关键概念,包括安装配置、项目构建...
《Maven实战》一书是针对Java开发人员深入学习和应用Maven构建工具的重要参考资料。Maven是一个项目管理和综合工具,它简化了构建、管理和部署Java项目的过程,通过标准化项目结构和自动化构建生命周期来实现这一...
### Maven实战 (Maven In Action) —— 关键知识点概览 #### 1. Maven简介与背景 **Maven** 是一款广泛应用于Java项目中的自动化构建工具,它以一种项目对象模型(POM)来管理项目的构建、报告和文档。通过简化项目...
SNAPSHOT表示这是一个开发中的版本,可能存在未解决的问题或待优化的地方,通常用于持续集成和开发过程中的测试。 全栈自动化测试实战不仅涵盖了前端界面的测试,还包括了后端接口的验证,以及移动应用的自动化测试...
《疯狂JAVA实战演义——源码》是一本深入解析JAVA编程实践的书籍,作者通过精心设计的15个实际应用开发案例,旨在帮助读者逐步掌握JAVA编程的核心技能,并提升其在实际开发中的应用能力。书中的每个实例都包含了完整...
Maven3培训教程.pptx MavenQuickReferenceCard.pdf MavenTheDefinitiveGuide.pdf Maven实战.pdf Maven实战——入门篇.pdf Maven学习.doc 持续集成之路——搭建Maven私服.doc 利用m2eclipse生成WTP项目.pdf
### Maven实战(中文版)——关键知识点解析 #### 一、Maven简介 Maven是一款由Apache软件基金会提供的项目管理和构建工具,它基于项目对象模型(Project Object Model, POM),通过一小段描述信息来管理项目的构建...
Maven3培训教程.pdf Maven实战.pdf MavenQuickReferenceCard.pdf MavenTheDefinitiveGuide.pdf Maven学习.doc 持续集成之路——搭建Maven私服.doc 利用m2eclipse生成WTP项目.pdf
项目概述:own_demo实战项目是基于Spring Boot的SSM框架整合实践,目前包含20个文件,主要采用Java语言开发。该项目集成了MyBatis-Plus、Druid数据源、Junit测试以及Swagger文档,实现了前后端分离的设计模式。项目...
Maven实战部分涵盖了从创建简单项目到定制多模块企业级项目的全过程。以创建一个简单的Maven项目为例,首先需定义项目的目标和依赖,然后编写项目对象模型(POM)文件,其中包含了项目的基本信息、构建配置和依赖...
《Maven实战》是一本实践导向的书籍,涵盖了Maven在实际项目中的应用,包括设置环境变量、配置构建服务器、集成持续集成工具如Jenkins,以及使用Maven进行部署。此外,它还介绍了一些高级话题,如使用Maven进行敏捷...
【标题】"eclipse使用maven整理文档"涵盖了在Eclipse集成开发环境中使用Maven进行项目管理和文档生成的实践知识。Maven是一个强大的Java项目管理工具,它通过配置文件(pom.xml)来管理项目的构建、依赖关系和文档...
这是一个基于Java的毕业设计项目,主要实现了对微博系统的模拟,采用了...这个项目不仅涵盖了Java Web开发的基本技术,还涉及到软件工程的最佳实践,对于Java毕业生来说是一个很好的实战练习,有助于提升综合开发能力。
- `m2e.zip`可能是一个Maven的Eclipse插件——M2E(Maven Integration for Eclipse),它将Maven集成到Eclipse IDE中,方便在IDE内进行Maven项目的管理。 ### 进阶使用 1. **依赖管理(Dependency Management)**...
这是一个基于Java技术栈,特别是SSM(Spring、SpringMVC、MyBatis)框架的毕业设计项目,主题为“民宿网站的设计与实现”。这个项目包含了完整的源代码和数据库设计,对于学习Java Web开发或者进行类似项目实践的...
在本项目"SpringBoot初学者综合项目实战——个人博客系统"中,我们将深入学习和实践SpringBoot框架,结合其他核心技术构建一个完整的个人博客系统。这是一个非常适合SpringBoot新手上手的项目,通过它,你可以理解并...