Maven
Maven已经进入成熟期,没什么大的变化了。风头会慢慢被Gradle之类的盖过去,但目前仍然是首选,因为它足够满足大部分项目的需求,而且懂的人非常多。
1.Sonatype
Maven被Sonatype主管后,中央仓库用Nexus管起来了。 用http://search.maven.org 就可以方便的找到jar。另外和Sun,Hibernate几家Repository的关系也好了,所有的jar都可以在中央库找到,不需要再同时指向多个Repository。
2.代理服务器与私服
如果机器不能直接上网,需要设定代理服务器,在maven目录的conf/settings.xml中,修改\小节。
如果连接中央服务器较慢,或者有项目内需要共享jar包,建议搭建一台私服,将下载后的包缓存起来供其他同事使用,私服选Nexus就很好。搭完私服后,可以在pom.xml里的\和\中增加私服定义。(参见springside-parent),也可以直接修改Maven的settings.xml的 \小节。
3. 版本选择与Enforcer插件
如果有多个项目都依赖了同一个依赖项,最终选择的版本并不是想当然的最高版本,历史因由是刚开始时大家的版本命名并不规范,单纯按数字/字母排序不一定对。所以,它选择了最近和最先原则。
- 最近原则: 如果A依赖B依赖C依赖D-2.0,同时A依赖E依赖D-1.0,此时D-1.0被选择,因为依赖路径更近。
最先原则: 如果大家依赖路径一样长,在pom.xml文件里位置靠前的那个赢。
maven的魅力与麻烦之一就是依赖和依赖的依赖,有时候一不小心就会因为隐性依赖一些不想依赖的库,比如用了slf4j就不想再出现commons-logging, 比如新版aspectj的groupId已经从aspejct改为org.aspectj了, enforcer插件可以提醒你这些隐性依赖,例子可见quickstart或parent的pom.xml。
另外,enforecer插件里定义\,能保证最后选择最高的版本,而不是上面所谓的最近最先原则。
另外,为免意外惊喜不断,quickstart里还用enforcer插件硬性规定了至少JDK6和Maven 3.0.3以上。
4.测试
4.1 区分单元测试与集成测试
原本Maven一直没有很好的区分单元测试和集成测试的用例。因为集成用例的依赖可能很多,执行又慢,很多时候我们都要Skip掉它们只运行单元测试。
后来Maven在原来的surefire插件继续负责在test阶段测试Test.java的单元测试用例, 新增了failsafe插件负责在integration-test阶段(package阶段之后)执行IT.java的集成测试。
但SpringSide在SpringSide4.0 RC2之后不再使用这个插件,首先因为springside是使用嵌入式Jetty,Out-Of-Container的执行功能测试用例的,所以在集成测试阶段之前的Package阶段打war包是白做的。其次继续把*IT.java用例继续放在test/java里,使得在Eclipse没有办法单独执行所有的单元测试。(因为Eclipse没有办法执行某个子目录及其子子目录下的所有用例)
所以SpringSide的综合解决办法是,用codehaus的build-helper-maven-plugin插件新开一个Functional Test Source 目录test/functional,将所有功能测试用例放到这里,然后文件名采用FT.java后缀,然后建不同的Profile,执行Test.java 或*FT.java.
在两个Examples项目的pom.xml中都有完整的示例,在eclipse:eclipse或m2e插件生成的项目文件里,都会包含新开的functional源码目录。
4.2 Skip Test
mvn install -Dmaven.test.skip=true 最狠的,连测试用例的编译都省掉了。
4.3 分组执行
TestNG的皇牌功能,可以将用例分成几组,比如超慢的Nightly组放到半夜才运行。 Junit4后来的新版也支持一个@Category的定义,但是,必须在一个TestSuite维护所有Case,或者使用一个叫ClassPathSuite的项目。
在Maven的测试插件里没这个麻烦,它会自行读取@Category标签来过滤。
pom.xml
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<groups>com.mycompany.FastTests</groups>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.12</version>
</dependency>
</dependencies>
</plugin>
TestCase中的testSlow()将不会被执行。
public class AppTest {
@Test
@Category(SlowTests.class)
public void testSlow() {
System.out.println("slow");
}
@Test
@Category(FastTests.class)
public void testFast() {
System.out.println("fast");
}
}
4.4 透传命令行的参数到测试插件
测试插件是自己Fork一个JVM出来的,所以启动Maven时的系统参数不会直接透传到测试中,比如我想在命令行控制selenium.driver,需要这样配置
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<selenium.driver>${selenium.driver}</selenium.driver>
</systemPropertyVariables>
</configuration>
</plugin>
5.脚本?脚本!!
虽然Maven的理想很丰满,什么都是插件,什么都是阶段,但实际项目还是有很多需要脚本干点小事情的时候,比如springside里更新本地测试数据库。这时候有两种选择,一种是完全用ant脚本,需要依赖包的时候用ant的maven插件,另一种是在maven里用antrun插件。
因为ant的maven插件老是被忘记下载,所以springside里选择了用maven的antrun插件,另外也不搞什么阶段了,定义出独立的profile,直接运行goal: mvn antrun:run -Prefresh-db
另外,exec:java来运行Java命令也不错。
6. Maven与Eclipse的集成
详见Maven2Eclipse 插件。
7. Archetype插件生成项目
8. 依赖及插件更新通知
- mvn versions:display-dependency-update 可显示 依赖更新
- mvn versions:display-plugin-update 可显示 插件更新
多模块时,在parent的pom文件处运行上述命令。
pom文件里需有这句, 插件更新的显示才靠谱。
<prerequisites>
<maven>2.2.1</maven>
</prerequisites>
插件更新通知看邮件列表: http://mail-archives.apache.org/mod_mbox/maven-announce/
9. Assembly插件
Maven的万能打包插件,可以除了标准的jar/war外,打包自己的发布包。在showcase中演示了如何打包一个可执行的War包。
资料
- 中文书:《Maven实战》 许晓斌。
- [《Maven: The Complete Reference 》] (http://books.sonatype.com/mvnref-book/reference/public-book.html) Sonatype出品的免费电子书。