original:http://www.blogjava.net/mlzry0612/archive/2011/07/11/223403.html
一.背景
Maven2 的基本原理很简单,采用远程仓库和本地仓库以及 pom(project object model).xml ,将 pom.xml 中定义的 jar 文件从远程仓库下载到本地仓库,各个应用使用同一个本地仓库的 jar ,同一个版本的 jar 只需下载一次,而且避免每个应用都去拷贝 jar 。如图 1 。同时它采用了现在流行的插件体系架构,只保留最小的核心,其余功能都通过插件的形式提供,所以在执行 maven 任务时,才会自动下载需要的插件。这个特性也为客户系统的升级带来的很大的方便,客户每次升级的时候可以使用maven的远程部署功能自动下载最新的系统组件(jar),并重新打包部署,很大程度的减少的系统升级的工作量。
理解Maven的原理,可以参考 Pear ――PHP扩展与应用库( the PHP Extension and Application Repository ),其原理非常类似,都有一个官方库,都是微内核,通过网络将需要的文件下载到本地,通过官方仓库将相应的类库进行统一管理。
Maven2的基本安装方法网上很多,就到http://maven.apache.org下载一个最新版,解压后即可,如果需要在命令行运行,还需要设置一些环境变量,网上的资料很多,这里就不多说了。总之,安装成功后当你在命令行下执行maven -version后正确显示当前maven的版本即可。
我们在项目中结合maven的进行开发的主要思路:
1.建立支持Maven2的开发框架,框架中结合了一些项目功能和工具类,并且此框架本身是一个eclipse工程,支持使用eclipse IDE的开发,并通过CVS可进行团队协作。
2.在Maven2的pom.xml中制定开发框架的依赖包,并建立依赖包的团队管理本地服务器,使团队中的包依赖得到统一管理。
3.每日下班后,在构建服务器上每日从cvs上下载各个团队开发人员的代码,统一进行集成构建和测试。由于是每日构建,所以发现的bug可及时反馈给开发人员进行修正,避免了一般开发过程中的bug长时间遗留的情况。
二.实施过程
为了实现上述思路,我们分几步实施:
1.首先需要构建一个系统的开发框架,
我们有两种方式构建,
其一是从零开始构建全新的框架,进入commond line,cd 到一个目录 ,执行
- mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=my-webapp -DarchetypeArtifactId=maven-archetype-webapp
mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=my-webapp -DarchetypeArtifactId=maven-archetype-webapp
执行完毕后接下来cd 到项目目录my-webapp下,执行
- mvn package
- mvn eclipse:eclipse
mvn package
mvn eclipse:eclipse
之后,打开eclipse,到其目录下导入项目,并手动编辑pom.xml文件,设定指定的jar包,比如加入一个jwebunit的jar包,我们需要在pom中添加一段:
- <dependency>
- <groupId>jwebunit</groupId>
- <artifactId>jwebunit</artifactId>
- <version>1.2</version>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>rhino</groupId>
- <artifactId>js</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
<dependency>
<groupId>jwebunit</groupId>
<artifactId>jwebunit</artifactId>
<version>1.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>rhino</groupId>
<artifactId>js</artifactId>
</exclusion>
</exclusions>
</dependency>
其中指定了包的名称,版本,使用的范围域等,pom.xml设置方式网上也是一堆一堆的,具体的可以自己搜搜。同时我们也可以使用maven2在 eclipse中的插件进行编辑,很方便,就不用记住那些该死的标签了。插件下载地址 http://m2eclipse.codehaus.org /update,将这个url填入到eclipse的Help-》Software Updates->find&install中新建一个插件下载地址的对话框中即可下载。
这种方式是完全自定义一个全新的工程后再进行框架搭建,比较累,尤其是添加依赖包的时候,需要根据自己的项目需要一个一个添加,很烦人,所以我们使用的第二个方法就直接找了一个现成的,到 Appfus 的网站http://appfuse.org/ 根据项目需要下载了一个项目框架作为原型,我们使用的是appfuse-light-webwork-ibatis- 1.8.2(webwork2.26,spring2.0,ibatis2.0),如果你使用的是其他的的技术,如 struts2,hibernate....直接到网站上下载一个相应的框架即可。appfuse框架使用maven2作为基本构建工具,其中自带的 pom.xml也替开发人员写好了,中所定义的依赖包可满足一般的开发需要,如需要自己指定的包,那么直接在其pom.xml中添加即可。要将这个框架作为eclipse工程使用,需要在解压后的框架目录下执行:
- mvn eclipse:eclipse -DdownloadSources=true
mvn eclipse:eclipse -DdownloadSources=true
这个命令会将工程将框架转换为eclipse工程,并从远程下载jar包到本地仓库(window下是(C:\Documents and Settings\${username}\.m2\repository),之后执行:
- mvn -Declipse.workspace=<path-to-eclipse-workspace> eclipse:add-maven-repo
mvn -Declipse.workspace=<path-to-eclipse-workspace> eclipse:add-maven-repo
其中path-to-eclipse-workspace是本机的eclipse的worksapce的路径。执行后maven会在eclipse中建立一个M2_REPO环境变量,并将其中所有的jar包引入到工程中,完全自动化,十分方便。
打开eclipse修改开发中的环境变量(我们项目中使用了Myeclipse插件),找到相应的工程,发现框架中已有一些代码,这是appfuse提供给开发人员的示例代码,我们可以按照自己以前项目的积累进行对框架进行完善,形成一套自己的开发框架,之后设置工程环境变量,在该项目中右键 ->Myeclipse->add web capabilities->指定该工作空间下的Src/main/webapps作为WEB工程的根路径,并指定修改JAVA Build Path中
- src/main/java
- src/main/resource
- src/test/java
src/main/java
src/main/resource
src/test/java
的三个soucrefolder的outputpath 为scr/main/webapp/WEB-Inf/class,这样设置的目的是便于开发人员在本地进行部署测试,否则按照appfuse原有的工程设置是不能进行顺利部署的。
至此,我们已经将Maven2结合到项目中,一开始可能对目录结构有些不适应,毕竟这是maven提供的项目框架格式,可以修改为自己习惯的,但是不建议这样做。设置完成后,cd到项目路径下,运行
- mvn test
- mvn package
- mvn install
mvn test
mvn package
mvn install
三个命令,均成功后,可上传到cvs/svn上面去,共享给项目组人员,各开发人员可直接使用,但有可能M2_REPO环境设置路径不一样(C:\Documents and Settings\${username}\.m2\repository,毕竟不是所有人都把系统装在C盘),需要手动修改一下。
2.建立开发团队内部仓库
为了便于团队的依赖包管理,我们不能全部使用官网的仓库,毕竟上面不具备我们项目开发所需要的所有的依赖包,所以我们需要为自己的团队建立一个内部仓库,可以自己管理所需的依赖包,建立一个内部仓库也十分简单(附录中我们会使用artifactory进行开发内部库建立):
首先需要一个 http server ,找台服务器装上 apache 就行。放一个空的 maven 目录到 htdocs 下,假设服务器 ip 为 192.168.0.1 ,确认能用 http://192.168.0.1/maven 访问到。
copy 本地仓库的jar包到服务器:对于 windows xp 来说一般在 C:\Documents and Settings\ % username%\.m2 下,其中% username %为操作系统登录用户名。这时你可以看到 ${user.home}/.m2/ 下有个 repository 目录,里面有很多的项目相关 jar ,目录按 groupId/ artifactId/version 排好。把 repository 目录整个拷贝到 apache 服务器的 maven 目录下,如果需要官方缺少的 jar 或公司内部 jar ,仿照这个目录结构,做好 jar 放到 maven 目录下。或者把包copy到本地,运行:
- mvn install:install-file -Dfile=X:/path/mail-1.3.jar -DartifactId=javamail -Dversion=1.3.1 -Dpackaging=jar -DgroupId=javamail
mvn install:install-file -Dfile=X:/path/mail-1.3.jar -DartifactId=javamail -Dversion=1.3.1 -Dpackaging=jar -DgroupId=javamail
开发人员要使用内部仓库,只需修改本地工程pom.xml ,在 repository 配置后加上:
- <repository>
- <id>companyName</id>
- <url>http:
- </repository>
<repository>
<id>companyName</id>
<url>http:// ${ip}/maven</url>
</repository>
3.每日构建
为了保证项目质量,尽早的发现项目中的bug,我们需要每日对系统进行构建,这也是我们使用maven的初衷之一,maven的几个命令就可帮助我们完成这项任务,当然我们可以使用持续构建工具与maven结合实现定时自动构建。构建方式:
- mvn test
- mvn package
- mvn install
mvn test
mvn package
mvn install
maven 会自动编译,测试,运行所有的testcase,这也要求我们的开发人员一定要按照规则编写单元测试代码,否则每日构建的意义就不大了。appfuse框架中提供了很好的单元测试代码,包括针对数据库层,业务逻辑层,web展示层等等,如果我们能很好的编写这些单元测试,那么对于系统后续的缺陷管理和控制是大有裨益的。
构建完成后或构建时需要对最新版本的项目进行部署,便于次日安排测试人员进行测试,maven提供多多种部署方式,在pom.xml进行项目的部署配置,不同的部署方式根据协议的不同,配置方式也有所差异:
以文件方式部署
- <project>
- [...]
- <distributionManagement>
- <repository>
- <id>proficio-repository</id>
- <name>Proficio Repository</name>
- <url>file:
- </repository>
- </distributionManagement>
- [...]
- </project>
<project>
[...]
<distributionManagement>
<repository>
<id>proficio-repository</id>
<name>Proficio Repository</name>
<url>file://${basedir}/target/deploy</url>
</repository>
</distributionManagement>
[...]
</project>
以SSH2方式部署
- <project>
- [...]
- <distributionManagement>
- <repository>
- <id>proficio-repository</id>
- <name>Proficio Repository</name>
- <url>scp:
- </repository>
- </distributionManagement>
- [...]
- </project>
<project>
[...]
<distributionManagement>
<repository>
<id>proficio-repository</id>
<name>Proficio Repository</name>
<url>scp://sshserver.yourcompany.com/deploy</url>
</repository>
</distributionManagement>
[...]
</project>
以SFTP方式部署
- <project>
- [...]
- <distributionManagement>
- <repository>
- <id>proficio-repository</id>
- <name>Proficio Repository</name>
- <url>sftp:
- </repository>
- </distributionManagement>
- [...]
- </project>
<project>
[...]
<distributionManagement>
<repository>
<id>proficio-repository</id>
<name>Proficio Repository</name>
<url>sftp://ftpserver.yourcompany.com/deploy</url>
</repository>
</distributionManagement>
[...]
</project>
以扩展SSH方式部署
目前为止上述3中方式已经被Maven包含,所以只要distributionManagement就可以了,但是使用扩展SSH命令部署的话你不仅需要配置distributionManagement还需要一个build extension,如下
- <project>
- [...]
- <distributionManagement>
- <repository>
- <id>proficio-repository</id>
- <name>Proficio Repository</name>
- <url>scpexe:
- </repository>
- </distributionManagement>
- <build>
- <extensions>
- <extension>
- <groupId>org.apache.maven.wagon</groupId>
- <artifactId>wagon-ssh-external</artifactId>
- <version>1.0-alpha-6</version>
- </extension>
- </extensions>
- </build>
- [...]
- </project>
<project>
[...]
<distributionManagement>
<repository>
<id>proficio-repository</id>
<name>Proficio Repository</name>
<url>scpexe://sshserver.yourcompany.com/deploy</url>
</repository>
</distributionManagement>
<build>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh-external</artifactId>
<version>1.0-alpha-6</version>
</extension>
</extensions>
</build>
[...]
</project>
The build extension specifies the use of the Wagon external SSH provider, which does the work of moving your files to the remote server. Wagon is the general purpose transport mechanism used throughout Maven.
以FTP方式部署
- <project>
- [...]
- <distributionManagement>
- <repository>
- <id>proficio-repository</id>
- <name>Proficio Repository</name>
- <url><A href="ftp://ftpserver.yourcompany.com/deploy</url>" target=_blank>ftp://ftpserver.yourcompany.com/deploy</url></A>
- </repository>
- </distributionManagement>
- <build>
- <extensions>
- <extension>
- <groupId>org.apache.maven.wagon</groupId>
- <artifactId>wagon-ftp</artifactId>
- <version>1.0-alpha-6</version>
- </extension>
- </extensions>
- </build>
- [...]
- </project>
<project>
[...]
<distributionManagement>
<repository>
<id>proficio-repository</id>
<name>Proficio Repository</name>
<url>ftp://ftpserver.yourcompany.com/deploy</url>
</repository>
</distributionManagement>
<build>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ftp</artifactId>
<version>1.0-alpha-6</version>
</extension>
</extensions>
</build>
[...]
</project>
一旦你配置好了相应的POM你可以执行下列命令来开始部署:
mvn deploy
同时也可通过执行一下命令生成此项目的站点报告,供项目参与人员使用。
mvn site
三. 结论
maven的强大显而易见,有很多其他的特性本文没有提及,如对各类插件的支持,以及对项目模块划分和继承关系的管理,这些都是maven的特性,也是 maven对项目生命周期的详尽诠释,有兴趣深入的TX可以下载我在附件中提供的教程《Better Builds With Maven2》.同时我也提供我根据appfuse建立的一套项目框架,可在myeclipse环境下使用,大家可以共同探讨完善。
附1:使用artifactory为Maven2团队开发建立内部开发仓库详解
在真正使用Maven后是为团队进行定制,所以我们不应使用官网的开发库,应在本地建立一个内部开发库对团队的jar包进行管理,所以我们首先搭建一个内部库环境,除文章上面所述的搭建Apache服务器方法外,我们还可以使用artifactory(下载地址:http://www.jfrog.org/sites/artifactory /latest/),一个很好的maven内部库的应用系统,下载后执行bin目录下的artifactory.bat命令即可。启动后可访问控制台http://内部库ip:8081/artifactory/验证服务是否成功启动。默认的用户名为admin,密码为password。artifactory最重要的是可配置第三方jar包,在deploy artifacts中加入并制定其groupId和artifactId即可
(不要忘记更改本地的pom.xml文件引入新加的jar包)。
在开发端我们需要更改全局配置文件setting.xml文件,将工程中setting.xml放入本地maven2->conf目录下,配置内部仓库的地址,只需要在setting.xml的mirrors元素中加入以下配置:
- <mirror>
- <id>emay local</id>
- <mirrorOf>central</mirrorOf>
- <name>emay local artifactory</name>
- <url>http:
- </mirror>
<mirror>
<id>emay local</id>
<mirrorOf>central</mirrorOf>
<name>emay local artifactory</name>
<url>http://内部库ip:8081/artifactory/repo</url>
</mirror>
这里要注意的是,在加入这段代码后我使用的appfuse框架中自带的应用服务器tomcat6进行构建,不能正常运行,报tomcat出错,把这段去掉或者在pom.xml中将应用服务器改为tomcat5.5后运行正常。看来maven还是有不少bug需要改进。
配置完成后再运行mvn install即可正常进行构建,maven会从本地内部库中寻找项目所依赖的jar包。运行mvn clean清除maven生成文件。
附2:maven2命令大全
validate,验证工程是否正确,所有需要的资源是否可用。
compile,编译项目的源代码。
test-compile,编译项目测试代码。
test,使用已编译的测试代码,测试已编译的源代码。
package,已发布的格式,如jar,将已编译的源代码打包。
integration-test,在集成测试可以运行的环境中处理和发布包。
verify,运行任何检查,验证包是否有效且达到质量标准。
install,把包安装在本地的repository中,可以被其他工程作为依赖来使用
deploy,在整合或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。
generate-sources,产生应用需要的任何额外的源代码,如xdoclet。