九、使用Hudson进行持续集成
1、持续集成的概念
持续集成(Continuout Integration)是最核心的敏捷实践之一。
简单地说,持续集成就是快速且高频率地自动构建项目的所有源码,并为项目成员提供丰富的反馈信息。
一次完整的集成往往会包括以下6个步骤:
【】持续编译:
所有正式的源代码都应该提交到源码控制系统中(如SVN),持续集成服务器按一定的频率检查源码控制系统,如果有新的代码,就触发一个继承,旧的已编译字节码应当全部清除,然后服务器编译所有最新的源码;
【】持续数据库继承:
源代码不仅仅包括Java代码,还可能包含SQL脚本,持续集成每次发现新的SQL脚本,就应该清理继承环境的数据库,重新创建表结构,并填入预备的数据。这样就能随时发现脚本的错误,基于脚本的测试还能发现其他相关问题;
【】持续测试:
除了自动化单元测试,集成阶段还要包含一些依赖外部环境的集成测试。所有这些测试都应该在每次集成的时候运行,并且在发生问题的时候能产生具体报告。
【】持续审查:
持续集成还应该使用各种工具生成各类报告,如测试覆盖率报告、Checkstyle报告、PMD报告等,当审查发现问题时,可以给开发人员反馈警告信息。
【】持续部署:
有些错误只有在部署后才能被发现,自动化部署能够帮助我们尽快发现这类问题。
【】持续反馈:
持续集成的最后一步的反馈,通常是一封电子邮件。基本规则是:将集成失败报告发送给这次集成相关的代码提交者,项目经理应该收到所有失败报告。
持续集成流程如下:
持续集成的意义:
【】尽早暴露问题:越早地暴露问题,修复问题代码的成本就越低。
【】减少重复操作:持续集成是完全自动化的,避免了大量重复的手工劳动。
【】简化项目发布:高频率的集成保证了项目随时都是可以部署运行的,没有持续集成,项目发布之前将不得不手动地集成,然后花大量精力修复集成问题。
【】建立团队信息:一个优良的持续集成环境能让团队随时对项目的状态保持信心,因为项目的大部分问题区域已经由持续集成环境覆盖了。
2、Hudson(Jenkins)简介
Hudson是流行的开源持续集成工具,它的优秀之处是提供了灵活的插件扩展框架,大量开发者基于这种机制对Hudson进行了扩展。
Hudson必须运行在JRE1.5或更高的版本上。
由于Hudson是Sun公司开发的,后来Oracle收购了Sun,所以Hudson的一个分身出走了,名字叫JenKins。
关于Hudson与Jenkins的关系,参看:http://www.oschina.net/news/63453/hudson-and-jenkins-grievances
(1)、安装Jenkins
下载地址:https://jenkins.io
3、准备版本控制系统
在正式创建Jenkins持续集成任务之前,需要准备好版本控制系统。常见的版本控制系统有CVS、SVN、Git、Mercurial等。
4、Jenkins的基本系统设置
在创建Jenkins持续集成任务之前,用户需要对Jenkins系统做一些基本的配置,包括JDK安装位置、Maven安装等信息。
5、创建Jenkins任务
可以创建多种任务类型,除非已经非常熟悉Jenkins,推荐选择free-style类型,因为这种方式更可控制,当任务出现问题的时候也更容易检查
(1)、任务的抛弃旧的构建设置:
Jenkins每执行一次构建任务,就可以保存相应的源代码、构建输出、构建报告等文件,可以选择一定的策略,清除旧的构建。
【】Days to keep builds:如果其值为非空的N,就仅保留N天之内的构建文件
【】Max # of builds to keep:如果#非空,就仅仅保留最大#个最近构建的相关文件
(2)、任务的源码仓库配置
(3)、任务的构建触发配置
有三种可选的触发构建方式:
【】Build after other projects are built:在其他项目构建完成之后构建本项目;
【】Build periodically:周期性地构建本项目;
【】Poll SCM:周期性地轮询源码仓库,发现有更新的时候构建项目
Poll SCM是常用的方式,其中配置的轮询的频率,使用了著名的UNIX任务调度工具Cron(http://en.wikipedia.org/wiki/Cron)所使用的配置方式。该配置方式使用5个字段表示不同的时间单位(字段之间用空格或制表符分隔):分 时 日 月 星期几
每个字段表示的意义及值范围分别为:
【】分:一小时中的分钟(0~59)。
【】时:一天中的小时(0~23)。
【】日:一月中的日期(1~31)。
【】月:月份(1~12)。
【】星期几:一周中的星期几(0~7,0和7都表示星期天)
还可以使用一些特殊的字符:
【】* :星号表示匹配范围内所有值。
【】M - N:连字符表示匹配M~N范围内的所有值,如“1 - 5”。
【】A, B, ..., Z :逗号表示匹配多个值,如“0, 15, 0”。
【】*/X或M-N/X:范围加上斜杠表示匹配范围内能被X整除的值,如“1~10/3”就等同于“3,6,9”。
例如:
【】* * * * *:每分钟
【】5 * * * *:每小时中的第5分钟。
【】*/10 * * * *:每隔10分钟。
【】45 10 * * 1- 5 :每周一到周五的上午10:45。
【】0,30 * 13 * 5 :每月13号的每半小时,或者每周五的每半小时。
(4)、任务的构建配置
6、监视任务状态、Jenkins用户管理
7、邮件反馈
持续集成中非常重要的一个步骤就是反馈,集成的状态信息必须及时地通知给相关团队成员。最常见的反馈方式就是使用电子邮件。
十、使用Maven构建Web应用
Maven对Web项目的布局结构也有一个通用的约定,首先,用户必须为Web项目显式指定打包方式为war。此外,Web项目的类几资源的默认位置都是src/main/java/和src/main/resources,测试类及测试资源文件的默认位置是src/test/java和src/test/resources/。Web项目有一个特殊的目录:Web资源目录,其默认位置为src/main/webapp/。
注意:WAR包中有一个lib目录包含所有依赖JAR包,但Maven项目结构中没有这样的目录,这是因为依赖都配置在POM中,Maven在用WAR方式打包的时候会根据POM的配置从本地仓库复制相应的JAR文件。
十一、版本管理
版本管理(Version Management)和版本控制(Version Control)的区别:
版本管理是指项目整体版本的演变过程管理;
版本控制是指借助版本控制工具(如SVN)追踪代码的每一个变更。
1、Maven的版本号定义约定
<主版本>.<次版本>.<增量版本> - <里程碑版本>
【】主版本:表示了项目的重大架构变更
【】次版本:表示较大范围的功能增加和变化,及Bug修复
【】增量版本:一般表示重大Bug的修复
【】里程碑版本:顾名思义,这往往指某个版本的里程碑。比如,alpha版本(内部测试版)表示不是非常稳定,还需要很多测试的版本; beta版本(公开测试版)表示相对alpha版要稳定一些,这个阶段的版本还会不断增加新功能;rc版本(候选版本),该版本比beta版更进一步,功能不再增加,相当于一个预览版本;stable版本(稳定版),最终发行的版本。
参看:http://blog.csdn.net/a3015440/article/details/6178568
2、自动化版本发布
Maven Release Plugin拥有这样的功能
3、GPG签名
十二、灵活的构建
典型的项目都会有开发环境、测试环境和产品环境,这些环境的配置不尽相同,那么在项目构建的时候就需要能够识别所在的环境并使用正确的配置。Maven为了支持构建的灵活性,内置了三大特性,即属性、Profile和资源过滤。
1、Maven属性
Maven中有6种属性:
【】内置属性:
主要有两个常用内置属性——${basedir}表示项目根目录,即包含pom.xml文件的目录;${version}表示项目版本。
【】POM属性:
使用该属性可以引用POM文件中对应元素的值。例如${project.artifactId}就对应了<project> <artifactId>元素的值。常用的属性包括:
* ${project.build.sourceDirectory}:项目的主源码目录,默认为src/main/java/。
* ${project.build.testSourceDirectory}:项目的测试源码目录,默认为src/test/java/。
* ${project.build.directory}:项目构建输出目录,默认为target/。
* ${project.outputDirectory}:项目主代码编译输出目录,默认为target/classes/。
* ${project.testOutputDirectory}:项目测试代码编译输出目录,默认为target/test-classes/。
* ${project.groupId}:项目的groupId。
* ${project.artifactId}:项目的artifactId。
* ${project.version}:项目的version,与${version}等价。
* ${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}-${project.version}。
【】自定义属性
用户可以在POM的<properties>元素下自定义Maven属性。例如:
<project>
...
<properties>
<my.prop>hello</my.prop>
</properties>
...
</project>
在POM中其他地方使用${my.prop}的时候会被替换成hello。
【】Settings属性
与POM属性同理,用户使用以settings.开头的属性引用settings.xml文件中XML元素的值。例如${settings.localRepository}指向用户本地仓库的地址.
【】Java系统属性
所有Java系统属性都可以使用Maven属性引用,例如 ${user.home}指向了用户目录。
【】环境变量属性
所有环境变量都可以使用以env.开头的Maven属性引用。例如${env.JAVA_HOME}指代了JAVA_HOME环境变量的值。
2、资源过滤
开发环境、测试环境、产品环境的配置往往不同,比如数据库配置,不同的环境可能数据地址、用户名、密码都不相同。如果手动处理,往往就意味着低效和错误。
资源文件的处理其实是maven-resources-plugin做的事情,它默认的行为只是将项目主资源文件复制到主代码编译输出目录中,将测试资源文件复制到测试代码编译输出目录中。但是通过一些POM配置,该插件就能够解析资源文件中的maven属性,即开启资源过滤。
Maven默认的主资源目录和测试资源目录的定义是在超级POM中。要为资源目录开启过滤,只需要在此基础上添加一行filtering配置即可。例如:
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
类似地,可以为测试资源目录开启过滤:
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
开启了资源过滤,就可以从资源文件中解析Maven属性。例如,对于数据库场景:
可以在配置数据库的地方使用Maven属性代替:
database.jdbc.driverClass=${db.driver}
database.jdbc.connectionURL=${db.url}
database.jdbc.username=${db.username}
database.jdbc.password=${db.password}
然后,在某个资源文件(即开启了资源过滤的目录下的文件)中定义这些属性,例如针对开发环境的数据库配置:
<profiles>
<profile>
<id>dev</id>
<properties>
<db.driver>com.mysql.jdbc.Driver</db.driver>
<db.url>jdbc:mysql://192.168.1.100:3306/test</db.url>
<db.username>dev</db.username>
<db.password>dev-pwd</db.password>
</properties>
</profile>
</profiles>
然后运行命令行:mvn clean install -P dev
其中:-P参数表示在命令行激活一个profile。这里激活了id为dev的profile。这样,项目构建完成后,输出目录中的数据库配置就是开发环境的配置了。
3、Maven Profile
为了能让构建的各个环境下方便地移植,Maven引入了profile的概念。profile能够在构建的时候修改POM的一个子集,或者添加额外的配置元素。用户可以使用很多方式激活profile,以实现构建在不同环境下的移植。
(1)、针对不同环境的profile
例如:下列代码同时加入了测试环境和产品环境的profile:
<profiles>
<profile>
<id>dev</id>
<properties>
<db.driver>com.mysql.jdbc.Driver</db.driver>
<db.url>jdbc:mysql://192.168.1.100:3306/test</db.url>
<db.username>dev</db.username>
<db.password>dev-pwd</db.password>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<db.driver>com.mysql.jdbc.Driver</db.driver>
<db.url>jdbc:mysql://192.168.1.100:3306/test</db.url>
<db.username>test</db.username>
<db.password>dev-pwd</db.password>
</properties>
</profile>
</profiles>
其中dev profile提供了开发环境数据库配置,而test profile提供了测试环境数据库配置。开发人员可以在使用mvn命令时在后面加上-P dev激活dev profile,而测试人员可以使用-P test 激活 test profile。
(2)、激活profile
Maven支持多种激活Profile的方式:
【】命令行激活
使用mvn命令行参数-P加上profile的id来激活profile,多个id之间以逗号分隔。例如:mvn clean install -P dev-x, dev-y // 激活dev-x和dev-y两个profile
【】settings文件显式激活
对于某个profile默认一直处于激活状态,就可以配置settings.xml文件的active-Profiles元素,表示其配置的profile对于所有项目都处于激活状态。例如:
<settings>
...
<activeProfiles>
<activeProfile>dev-x</activeProfile>
</activeProfiles>
...
</settings>
【】系统属性激活
用户可以配置当某些系统属性存在的时候,自动激活profile,例如:
<profiles>
<profile>
<activation>
<property>
<name>test</name>
<value>x</value>
</property>
</activation>
...
</profile>
</profiles>
用户可以在命令行声明系统属性,例如mvn clean install -D test=x
因此,这种方式也是从命令行激活profile的防范,而且多个profile完全可以使用同一个系统属性来激活。
【】操作系统环境激活
Profile还可以自动根据操作系统环境来激活。例如:
<profiles>
<profile>
<activation>
<os>
<name>Windows XP</name>
<family>Windows</family>
<arch>x86</arch>
<version>5.1.2600</version>
</os>
</activation>
...
</profile>
</profiles>
这里的family的值包括Windows、UNIX和Mac等,其他几项name、arch、version是系统属性os.name、os.arch、os.version。
【】文件存在与否激活
Maven能够根据项目中某个文件存在与否来决定是否激活profile,例如:
<profiles>
<profile>
<activation>
<file>
<missing>x.properties</missing>
<exists>y.properties</exists>
</file>
</activation>
...
</profile>
</profiles>
上述代码,当项目中存在y.properties,且不存在x.properties时激活该profile。
【】默认激活
用户可以在定义profile的时候指定其默认激活,例如:
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
...
</profile>
</profiles>
注意: 如果POM中有任何一个profile通过上述前几种方式中的任意一种方式被激活了,所有的默认激活配置都会失效。
通过maven-help-plugin来帮助用户了解当前哪些profile被激活,有哪些profile等。例如:
mvn help:active-profiles // 了解当前激活的profile
mvn help:all-profile // 列出当前所有的profile
(3)、profile的种类
根据具体的需要,可以在不同的位置使用profile:
【】pom.xml:在pom.xml中声明的profile只对当前项目有效。
【】用户settings.xml:用户目录下.m2/settings.xml中的profile对本机上该用户所有的Maven项目有效。
【】全局settings.xml:Maven安装目录下conf/settings.xml中的profile对本机上所有的Maven项目有效。
【】profiles.xml(Maven 2):项目根目录下使用一个额外的profiles.xml文件来声明profile,该特性在Maven 3中被移除,建议这类profile移到settings.xml中。
不同类型的profile中可以声明的POM元素也是不相同的:pom.xml中的profile能够随着pom.xml一起被提交到代码仓库中、被Maven安装到本地仓库中、被部署到远程Maven仓库中等,因此这种类型的profile可以修改或者增加很多POM元素,如下:
<project>
<repositories> </repositories>
<pluginRepositories> </pluginRepositories>
<distributionManagement> </distributionManagement>
<dependencies> </dependencies>
<dependencyManagement> </dependencyManagement>
<modules> </modules>
<properties> </properties>
<reporting> </reporting>
<build>
<plugins> </plugins>
<defaultGoal> </defaultGoal>
<resources> </resources>
<testResources> </testResources>
<finalName> </finalName>
</build>
</project>
与pom.xml中的profile对应的,其他几种外部profile,由于无法保证它们跟随特定的pom.xml一起被分发,因此Maven不允许它们添加或者修改绝大部分的pom元素。这些profile仅仅能用来影响项目的仓库和Maven属性。
(4)、在profile中激活集成测试
很多项目都有大量的单元测试和集成测试,单元测试的粒度较细,运行较快,集成测试粒度较粗,运行比较慢。在构建项目或者做持续集成时,我们希望单元测试尽量高频度地执行,集成测试尽量低频度地执行。
TestNG中组的概念支持单元测试和集成测试的分类标记。例如@Test(group={"unit"}) 表示测试方法属于单元测试;@Test(groups={"integration"})表示某个测试为集成测试。
然后,可以使用下列方式告诉maven默认只执行所有的单元测试,只在特定的时候才执行集成测试,例如:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artigactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<groups>unit</groups>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>full</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artigactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<groups>unit,integration</groups>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
有了上述配置,用户就可以根据实际情况配置持续集成服务器,例如每隔15分钟检查源码更新,如有更新执行一个默认构建,即只包含单元测试,此外,还可以配置一个定时任务。例如,每天执行两次,执行一个激活full profile的构建,以包含所有的集成测试。
十三、生成项目站点
1、项目报告插件
(1)、JavaDocs 生成项目文档
(2)、Source Xref 查看项目最新源代码
(3)、CheckStyle 自动检查Java代码编码规范
(4)、PMD Java源码分析工具(包括潜在的bug、无用代码、可优化代码、重复代码、过于复杂的表达式等)
(5)、ChangeLog 源码变更报告生成工具
(6)、Cobertura 测试覆盖率报告生成工具
2、自定义站点外观
3、创建自定义页面
4、国际化
5、部署站点(FTP、SCP、DAV)
十四、m2eclipse
1、创建、导入Maven项目
2、执行Maven命令
3、访问Maven仓库
4、管理项目依赖
十五、编写Maven插件
Maven的任何行为都是由插件完成的,大量的Maven插件可以从Aapche和Codehaus获得,几乎能满足所有Maven项目的需要,此外,还有很多Maven插件分别在Googlecode、Sourceforge、Github等项目托管服务中。
在一些非常情况下,如果有非常特殊的需求,并且无法找到现成的插件可供使用,那么用户可以自己编写Maven插件。编写一个Maven插件也不复杂。
十六、Archetype
使用Maven Archetype可以快速生成项目骨架,可以将Archetype理解成Maven项目的模板。许多开源项目都提供了自己的Archetype方便用户快速创建项目。用户也可以创建自己的Archetypebig进行维护。
1、Maven Archetype Plugin
Archetype是通过Maven Archetype Plugin插件来实现的。