灵活的构建
一个优秀的项目的构建必须足够灵活,可以使项目在不同的环境下都能构建成功,比如,典型的项目都会有开发环境、测试环境、生产环境,这些环境的配置参数不同,那么项目构建的时候就应该根据不同的环境使用相应的配置,当有很多集成测试的时候,也不是每次构建都需要运行测试的,因此也需要在特定的情况下激活集成测试的运行。
maven为了支持构建的灵活性,内置了三大特性,即属性、profile、资源过滤。这里介绍下这些特性的使用。
<!--maven属性--> <properties> <!--指定maven读取文档和源码编码--> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!--指定maven用什么编码呈现站点的html文档--> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!--依赖归类--> <org.springframework.version>4.3.10.RELEASE</org.springframework.version> <javax.mail.version>1.4.1</javax.mail.version> <com.icegreen.version>1.3.1b</com.icegreen.version> <testng.version>6.13.1</testng.version> <dom4j.version>1.6.1</dom4j.version> </properties>
<dependencies> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version> <scope>test</scope> </dependency> </dependencies>
如上,就是一个maven属性最常见的使用方式,自定义maven属性,然后在pom的其他地方用${属性名}的方式引用属性,这种做法的最大意义在于消除重复,重复越多,好处就越明显,降低了以后升级版本的工作量,同时也降低了错误发生的概率,这不是maven属性的全部,这实际上只是maven的6类属性中的一类,这六类属性分别为:
1.内置属性:主要有两个常用的内置属性,${basedir}表示项目根目录,即包含pom.xml文件的目录,${version}表示项目版本。
2.pom属性:用户可以使用该类属性引用pom文件中对应元素的值,例如${project.artifactId}就对应了<project><artifactId>
元素的值,常用的pom属性包括:
${project.build.sourceDirectory}:项目的主源码目录,默认为:src/main/java
${project.build.testSourceDirectory}:项目的测试源码目录,默认为:src/test/java
${project.build.directory}:项目构建输出目录,默认为:target/
${project.build.outputDirectory}:项目主代码编译输出目录,默认为:target/classes/
${project.build.testOutputDirectory}:项目测试代码编译输出目录,默认为:target/test-classes/
${project.groupId}:项目的groupid。
${project.artifactId}:项目的artifactId。
${project.version}:项目的version,与${version}等价。
${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}-${project.version}。
这些属性都对应了一个POM元素,它们中一些属性的默认值都是在超级pom中定义的。
自定义属性:用户可以在pom的<properties>元素下自定义maven属性,例如:
<project> ... <!--maven属性--> <properties> <dom4j.version>1.6.1</dom4j.version> </properties> ... </project>
然后在pom中其他地方使用${dom4j.version}的时候会被替换成1.6.1
settings属性:与POM属性同理,用户使用以settings. 开头的属性引用settings.xml文件中XML元素的值,
如${settings.localRepository}指向用户本地仓库的地址。
java系统属性:所有java系统属性都可以使用maven属性引用,例如${user.home}指向了用户目录。用户可以使用
mvn help:system,查看所有的java系统属性。
环境变量属性:所有环境变量都可以使用以env.开头的maven属性引用,例如${env.JAVA_HOME}指代了JAVA_HOME环境变量
的值,用户可以使用mvn help:system,查看所有的环境变量。
正确使用这些maven属性,可以帮助我们简化POM的配置和维护工作,例如:
<dependency> <groupId>${project.groupId}</groupId> <artifactId>account-service</artifactId> <version>${project.version}</version> </dependency>
在一个多模块项目中,模块之间的依赖比较常见,这些模块通常会使用同样的groupid和version,因此这个时候就可以使用pom属性,上述配置表示依赖的模块和当前模块的groupid和version一致,这样当项目版本升级的时候就不用修改依赖构件的版本了。在插件中也大量应用了maven属性。
从上面的内容中可以看出,maven属性能让我们在pom中方便的引用项目环境和构建环境的各种十分有用的值,这是创建灵活构建的基础,下面将会结合profile和资源过滤,展示maven能够为构建提供的更多的可能性。
构建环境的差异
举个例子,比如说我们平常使用的时候,测试环境用的项目配置信息、生产环境用的配置信息、开发环境用的配置信息,最常见的是使用不同的数据库,我们常用的方式是手动去修改这些信息,但是手动修改就意味着低效和不灵活,maven提供灵活的构建,可以根据不同的情况采用不同的配置去构建项目。
资源过滤
为了应对环境的变化,首先使用maven属性将这些会变化的部分提取出来,例如数据库的properties配置文件,如下:
account-web.properties
database.jdbc.driverClass=${db.driver} database.jdbc.connectionURL=${db.url} database.jdbc.username=${db.username} database.jdbc.password=${db.password}
数据库的配置会发生变化,所以用maven属性取代他们,如下:
pom.xml中
<!--构建环境配置--> <profiles> <!--开发环境配置--> <profile> <id>dev</id> <properties> <db.driver>db-driver</db.driver> <db.url>db-url</db.url> <db.username>db-username</db.username> <db.password>db-password</db.password> <properties/> </profile> </profiles>
上面的两个定义还不够,默认情况下maven只是将资源文件复制到构建输出目录,但是properties中使用的maven属性占位符并不会自动替换成maven属性的实际值,我们需要对资源文件开启过滤功能,才可以替换为属性值,配置如下:
<!--设置主要资源文件过滤(maven属性替换)--> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <!--设置测试资源文件过滤(maven属性替换)--> <testResources> <testResource> <directory>src/test/resources</directory> <filtering>true</filtering> </testResource> </testResources>
这样配置之后,我们就可以通过命令激活profile,构建相应环境的构件,命令如下:
mvn clean install -Pdev
maven的-P参数表示在命令行激活一个profile,上述命令激活了一个id为dev的profile,构建完成后,properties中的maven属性占位符就替换为实际的maven属性值了。
maven profile
从前面内容我们看到,不同环境的构建很可能是不同的,典型的情况就是数据库的配置,除此之外,有些环境可能需要配置插件使用本地文件,或者使用特殊版本的依赖,或者需要一个特殊的构件名称。要想使得一个构建不做任何修改就能在任何环境下运行,往往是不可能的,为了能让构建在任何环境下方便的移植,maven引入了profile的概念。profile能够在构建的时候修改一个pom的子集,或者添加额外的配置元素,用户可以使用很多方式激活profile,以实现构建在不同环境下的移植。
1.针对不同环境的profile
<!--构建环境配置--> <profiles> <!--开发环境配置--> <profile> <id>dev</id> <properties> <db.driver>db-driver</db.driver> <db.url>db-url</db.url> <db.username>db-username</db.username> <db.password>db-password</db.password> <properties/> </profile>
<!--测试环境配置--> <profile> <id>test</id> <properties> <db.driver>db-driver-test</db.driver> <db.url>db-url-test</db.url> <db.username>db-username-test</db.username> <db.password>db-password-test</db.password> <properties/> </profile> </profiles>
上面的配置可以使用-Pdeb、-Ptest 来激活不同环境的配置。
2.激活profile
命令行激活:mvn clean install -Pabc,def 通过命令行-P加profile的id来激活profile,多个id之间用逗号(,)分隔。
settings文件显示激活:如果用户希望某个profile默认一直处于激活状态,就可以配置setting.xml文件的activeProfiles元素,表示其配置的profile对于所有项目都处于激活状态,settings中配置如下:
<settings>
......
<activeProfiles>
<activeProfile>dev</activeProfile>
</activeProfiles>
......
</settings>
系统属性激活:用户可以配置当某系统属性存在的时候,自动激活profile,配置如下:
<!--构建环境配置--> <profiles> <!--开发环境配置--> <profile> <activation> <property> <name>test</name> <value>x</value> </property> </activation> <properties> <db.driver>db-driver</db.driver> <db.url>db-url</db.url> <db.username>db-username</db.username> <db.password>db-password</db.password> <properties/> </profile> </profiles>
上述配置进一步配置,当系统属性存在,并且等于x时才激活。
用户可以在命令行声明系统属性,mvn clean install -Dtest=x,这也算是一种命令行激活的一种方式,而且多个profile可以通过同一个系统属性来激活。
操作系统环境激活:profile还可以自动根据操作系统环境激活,如果构建在不同的操作系统有差异,用户完全可以将这些差异写进profile,然后配置他们自动基于操作系统环境激活。
<!--构建环境配置--> <profiles> <!--开发环境配置--> <profile> <activation> <os> <name>WindowsXP</name> <family>Windows</family> <arch>X86</arch> <version>5.1.2600</version> </os> </activation> <properties> <db.driver>db-driver</db.driver> <db.url>db-url</db.url> <db.username>db-username</db.username> <db.password>db-password</db.password> <properties/> </profile> </profiles>
文件存在与否激活:maven能够根据项目中某个文件存在与否来决定是否激活profile,
<!--构建环境配置--> <profiles> <!--开发环境配置--> <profile> <activation> <file> <exists>x.properties</exists>存在这个文件激活 <missing>y.properties</missing>没有这个文件激活 </file> </activation> <properties> <db.driver>db-driver</db.driver> <db.url>db-url</db.url> <db.username>db-username</db.username> <db.password>db-password</db.password> <properties/> </profile> </profiles>
默认激活:用户可以在定义profile的时候指定其默认激活,如果显示指定了激活,那么所有默认失效。
<!--构建环境配置--> <profiles> <!--开发环境配置--> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <db.driver>db-driver</db.driver> <db.url>db-url</db.url> <db.username>db-username</db.username> <db.password>db-password</db.password> <properties/> </profile> </profiles>
如果项目中有多个profile定义,我们可以通过help插件查看当前激活的所有profile,命令如下:
mvn help:active-profiles
该插件还有另外一个目标,又来列出当前所有的profile,命令如下:
mvn help:all-profiles
profile的种类
pom.xml:pom中声明的profile只对当前项目有效。
用户settings.xml:对本机上该用户的所有maven项目有效。
全局settings.xml:对本机上的所有maven项目有效。
不同类型的profile可以声明的pom元素也是不同的,pom中profile可以配置的pom元素如下:
<project> <repositories></repositories> <pluginRepositories></pluginRepositories> <distributionManagement></distributionManagement> <developers></developers> <dependencyManagement></dependencyManagement> <modules></modules> <properties></properties> <reporting></reporting> <build> <plugins></plugins> <defaultGoal></defaultGoal> <resources></resources> <testResources></testResources> <finalName></finalName> </build> </project>
其他profile可以使用的pom元素如下:
<project> <repositories></repositories> <pluginRepositories></pluginRepositories> <properties></properties> </project>
web资源过滤
web资源过滤需要通过war插件做配置,配置如下:
<!--web资源过滤配置--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <webResources> <resource> <filtering>true</filtering> <directory>src/main/webapp</directory> <includes> <include>**/*.css</include> <include>**/*.js</include> </includes> </resource> </webResources> </configuration> </plugin>
上述配置中,也可以配置排除哪些文件。
在profile中激活集成测试
利用testNG的组的概念,可以把单元测试和集成测试按组分开,然后在不同的profile中配置进行测试的不同的组,这种配置方式对于持续集成也是有用的。