一、咱们天天除了编写源代码之外,有至关一部分时间花在了编译、单元测试、生成报告、打包和部署等繁琐的且不起眼的工做上,这就是构建.maven是一个异常强大的构建工具,能帮咱们自动化构建过程,从清理、编译、测试到生成报告,再到打包部署.java
二、几乎全部的Java应用都会用到第三方类库,随着类库的增多,版本不一致,版本冲突,依赖臃肿等问题接踵而来,针对这些问题maven提供了优秀的解决方案,它经过一个坐标系统准肯定位每个构建,为这个类库世界引入了经纬,咱们能够借助它来有序管理依赖.linux
一、首先安装jdk.
web
二、下载解压apache-maven-3.0-bin.tar.gz. 命令:算法
tar -xzf apache-maven-3.0-bin.tar.gz
三、推荐在安装目录旁平行的建立一个符号连接,方便往后的升级,不用每次都更新环境变量,只需更新符号连接指向新的版本maven便可.命令:spring
ln -s apche-maven-3.0 apache-maven
四、设置maven环境变量 略.数据库
五、检查Maven安装apache
mvn -v
六、设置HTTP代理,若是公司基于安全考虑,须要代理访问英特网,就须要为Maven配置HTTP代理,才能访问外部仓库,已下载所需资源,编辑M2_HOME/conf/settings.xml中的proxies标签,略,windows
七、设置MAVEN_OPTS环境变量值为 - Xms128m - Xmx512m,默认的能够可用内存每每不能知足maven的须要.设计模式
八、配置用户范围的settings.xml,~/.m2下也有一个settings.xml,建议日常修改它,这样Maven升级时,无需再拷贝它,感受怎么都行.缓存
九、修改IDE默认的maven,编辑Windows->Perferences->Installation,去掉Embedded Maven,而后Add选择M2_HOME安装目录勾选.
一、编写POM(定义项目的基本信息,描述项目如何构建,声明项目依赖等).
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!-- 指定了当前POM模型的版本,对于Maven2及Maven3来讲,它只能是4.0.0 -->
<modelVersion>4.0.0</modelVersion>
<!-- 最重要的三项, groupId, artifactId,version定义了一个项目的基本坐标 -->
<!-- 定义项目属于哪一个组,好比org.springframework -->
<groupId>com.wangwei</groupId>
<!-- 定义了当前项目在上面那个组中的惟一ID(一个组下面能够有多个项目) -->
<artifactId>hello-world</artifactId>
<!-- 当前项目的版本,好比此处的1.0的快照版本,快照指项目还处于开发中,并不稳定 -->
<version>1.0-SNAPSHOT</version>
<!--声明了一个对于用户更为友好的项目名称,虽然这不是必须的 -->
<name>Maven Hello World Project</name>
</project>
二、编写主代码
1>项目的最代码会被打包到最终的jar中,而测试代码只在测试时用到,不会被打包,主代码位于src/main/java目录,咱们遵循约定在该目录下建立文件com/wangwei/helloworld/HelloWorld.java,程序打印一个字符串,这里注意通常来讲Java类的包名应该基于项目的groupId和artifactId,这样清晰复合逻辑,方便找Java类.
2>运行mvn clean compile进行编译,clean清理输出目录target/,compile编译项目主代码.
三、编写测试代码
1>修改POM以下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wangwei</groupId>
<artifactId>hello-world</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Maven Hello World Project</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
有了这段声明,Maven就能自动从中央仓库下载junit-4.7.jar,scope为依赖范围,test表示只对测试有效,主代码中import junit会报错,不声明scope默认是compile,对主代码测试代码都有效.
2>Maven项目默认的测试代码目录src/test/java,在该目录下建立HelloWorld打印一段话,约定测试类都已Test结尾,方法都已test开头.
3>执行mvn clean test命令,maven实际执行的不止这俩个任务,还有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile,也就是在test执行以前会自动执行项目主资源处理,主代码编译,测试资源处理,测试代码编译等工做,这是maven生命周期的特性,后面详解;从输出还能够看到maven从中央仓库下载了junit-4.7.pom和junit-4.7.jar到本地仓库(~/.m2/respository)中,共全部maven项目使用;从输出还看到在执行compiler:testCompile任务失败了,这是因为历史缘由,maven核心插件之一的compiler默认只支持Java 1.3,须要配置支持1.5,代码以下(也可在settings.xml中进行全局设置):
<project> ... <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
四、打包和运行
1>HelloWorld中POM中没有指点打包类型默认是jar,执行mvn clean package进行打包,相似的maven在打包以前会执行编译,测试等操做,这里看到jar:jar任务负责打包,实际就是jar插件的jar目标将项目的主代码打包成一个hello-world-1.0-SNAPSHOT.jar文件,该文件位于target/输出目录中,还能够根据finalName定义该文件的名称.
2>咱们获得了项目的输出,若是有须要的话,就能够复制这个jar文件到其它项目的ClassPath中从而使用HelloWorld类,可是,其余项目怎么直接引用这个jar呢,还须要一个步骤mvn clean install,从输出能够看到该任务将输出的jar安装到 了maven的本地仓库中,这样其余项目就可以使用了.相似的install以前会执行package.
3>到目前为止尚未运行项目,HelloWold类有一个main方法,默认打包的jar是不能直接运行的,由于带有main方法的类信息不会添加到manifest中(jar文件的META-INF/MANIFEST_MF中没法看到Main-Class一行),为了生成可执行的jar,须要借助maven-shade-plugin插件,配置以下(<project><build><plugins>下面):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com/wangwei/helloworld/HelloWorld.java</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
执行Java -jar target\hello-world-1.0.SNAPSHOT.jar能够正常看到输出.
五、Archetype插件能够根据咱们提供的信息建立项目的骨架,执行mvn archetype:generate便可,实际开发使用IDE建立Archetype.
六、m2eclipse简单使用,导入maven项目,建立maven项目,运行maven构建,略.
一、简单依赖配置groupId、artifactId、version、packaging、scope略.
二、传递性依赖,例:account-mail中有个spring-core依赖,spring-core里又有一个commons-logging依赖,那么commons-logging就是account-mail的一个传递性依赖,有传递性依赖机制,在使用spring framework的时候就不用考虑它依赖了什么,也不用担忧引入多余的依赖,Maven会解析各个直接的依赖POM,并将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中.
三、依赖调解,maven引入传递性依赖机制,大大简化和方便了依赖声明,另外一方面咱们只须要关系直接依赖,而不用考虑这些直接依赖会引入什么传递性依赖,可是当传递性依赖形成问题的时候,就须要清楚的知道该传递性依赖是从那条依赖路径引入的.例如:A->B->X(1.0);A->X(2.0),两条路径上有两个不一样版本的X,那么哪一个X会被maven解析使用呢,Maven依赖调解的第一原则:路径最近者优先,若是路径相同,第二原则:第一声明者优先,也就是在POM中的声明顺序.
四、可选依赖<optional>,例如A->B、B->X(可选)、B->Y(可选),这里的X、Y就是A的传递性依赖,但因为这里是可选的,依赖不会传递,若是A中要用X和Y时,还须要在A中声明,这玩意有吊用.
五、排除依赖<exclusions>,好比当前项目A->B->X(SNAPSHOT),X不稳定,这时就须要排除这个传递依赖,手动声明该类库的正式版,还有些状况,如A->B->X,X因为版权的缘由不在中央仓库,而C->X,C项目有一个对应的实现,就能够排除B中的X,采用C中的.代码:
<dependency>
<groupId>org.unitils</groupId>
<artifactId>unitils-testng</artifactId>
<version>${unitils.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>//exclusino能够有多个
<artifactId>junit</artifactId>
<groupId>junit</groupId>
</exclusion>
</exclusions>
</dependency>
六、使用maven属性归类依赖,其实就是把版本一致的抽出来统必定义,例spring framework:
<properties>
<org.springframework.version>3.2.8.RELEASE</org.springframework.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
一、坐标和依赖是任何一个构建在maven世界中的逻辑表示方式;而构建的物理表示方式是文件,maven经过仓库来统一管理这些文件.
二、何为maven仓库,好比咱们一台服务器有几十个项目,这些项目都用到了log4j,struts2等jar,在非maven项目中咱们每每能发现lib的目录,各个项目的lib存在大量的重复,得益于坐标机制,maven项目中使用任何一个构建的方式都是彻底相同的,再次基础上,maven能够在某个位置统一存储全部maven项目共享的构建,这个统一的位置就是仓库,实际的maven项目将不在各自存储其依赖文件,他们只须要声明这些依赖的坐标,在须要的时候,maven会自动根据坐标找到仓库中的构建,并使用它们.
三、仓库的布局,也就是jar存储路径与坐标的对应关系,以下:groupId/artifactId/version/artifactId-version.packaging.
四、仓库的分类,本地仓库和远程仓库,maven寻找构建时首先查看本地,有则直接使用,没有则去远程仓库查找,发现就下载到本地仓库使用,若是远程也没有则报错.中央仓库是Maven核心自带的远程仓库,私服是另外一种特殊的远程仓库,是为了节省带宽和时间在局域网内架设的一个私有仓库服务器,内部的项目还能部署到私服上供其余项目使用.除了中央仓库和私服,还有不少公开的远程仓库.
本地仓库
一、本地仓库默认位置,windows:C:\users\wangwei\.m2\repository,Linux:/home/wangwei/.m2/repository/,linux(.)开头文件隐藏,ls -a查看,能够自定义本地仓库目录地址,编辑~/.m2/settings.xml,默认settings.xml是不存在的,须要从$M2_HOME/conf/settings.xml复制过去,再进行编辑,建议这么作,而不是直接修改全局目录的settings.xml.
二、一个构建只有在本地仓库中以后,才能被其它maven项目使用,构建进入本地仓库的两种方式,一是从远程仓库下载,二是将本地项目安装到本地仓库,mvn clean install命令将项目的构建输出安装到本地仓库.
三、本地仓库相似书房只有一个,远程仓库相似书店,有不少.
中央仓库
中央仓库是一个默认的远程仓库,maven的安装文件自带了中央仓库的配置,$M2_HOME/lib/maven-model-builder-3.0.jar中:
<repositories>
<repository>
<id>central</id>
<name> Maven Repository Switchboard</name>
<layout> default</layout>
<url> http://repo1.maven.org/maven2</url>
<snapshots>
<enabled> false</enabled>
</snapshots>
</repository>
</repositories>
私服
一、私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网的远程仓库,共局域网的maven用户使用,当须要下载构件的时候,它会先从私服请求,若是私服不存在,再从远程下载,缓存在私服上以后,再为maven的下载提供服务,一些没法从外部仓库下载的构件也能从本地上传到私服上供你们使用.
二、私服的好处:节省本身的网络带宽,加速maven构件,部署第三方构件,提升稳定性,下降中央仓库的负荷.
远程仓库的配置
一、有时默认的中央仓库没法知足项目的需求,可能在JBoss Maven仓库,POM中配置该仓库:
<repositories>
<repository>
<id>jobss</id>
<name>JBoss Repository</name>
<layout>default</layout>
<url>http://repository.jboss.com/maven2/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
对于releases和snapshots来讲,除了enabled,还有两个元素updatePolicy和checksumPolicy,updatePolicy配置远程仓库检查更新的频率,默认值为daily(天天一次),还有nerver、always(每次构件都检查更新)、inteval:X(每隔X分钟检查一次);checksumPolicy用来配置maven检查检验和文件的策略,略.
远程仓库的认证
大部分远程仓库无需认证就能够访问,可是有时候出于安全方面的考虑,咱们须要提供一些认证信息才能访问一些远程仓库.配置认证信息和配置仓库信息不一样,认证信息必须配置在settings.xml文件中.假设为一个id为my-proj的仓库配置认证信息,编辑settings.xml文件以下:
<settings> ... <servers>
<server>
<id>my-proj</id>//这个id必须和POM中须要认证的repository元素id一致
<username>admin</username>
<password>password</password>
</server> ... </settings>
部署至远程仓库
一、私服的一大做用是部署第三方构件,编辑pom.xml,配置distributionManagement:
<distributionManagement>
<repository>
<id>pro-release</id>
<name>Proj Release Repository</name>
<url>http://localhost:8081/nexus/content/repositories/RestBus-Releases</url>
</repository>
<snapshotRepository>
<id>pro-snapshot</id>
<name>Proj Snapshot Repository</name>
<url>http://localhost:8081/nexus/content/repositories/RestBus-Snapshots</url>
</snapshotRepository>
</distributionManagement>
二、往远程仓库部署构件的时候,每每须要认证,配置已讲,注意id一致便可,配置正确后,运行命令:mvn clean deploy,maven就会将输出构件部署到私服,若是是快照就部署到快照仓库,发布版就部署到发布版仓库.
镜像
一、若是仓库X能够提供仓库Y存储的全部内容,那么X就是Y的一个镜像,例,中央仓库在中国有镜像,因为地理文职的因素,这个镜像能提供比中央仓库更快的服务,所以,能够配置maven使用该镜像来替代中央仓库.编辑settings.xml:
<settings> … <mirrors>
<mirror>
<id> maven-net-cn</id>
<name> Maven China Mirror</name>
<url> http://maven.net.cn/content/groups/public/</url>
<mirrorOf>central</mirrorOf>//中央仓库id
</mirror>
</mirrors> … </settings>
任何对于中央仓库的请求都会转发至该镜像,用户也能够用一样的方式来配置其它仓库的镜像.
二、关于镜像的一个更为常见的用法是结合私服,因为私服是代理任何外部公用仓库的,所以私服就是全部仓库的镜像,编辑settings.xml:
<settings> ... <mirrors>
<mirror>
<id>internal-repository</id>
<name>Internal Repository Manager</name>
<url>http://192.168.1.100/maven2</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors> ... </settings>
仓库搜索服务-也就是如何查找须要的依赖,略.
maven使用中,命令行的输入就对应了生命周期,maven的生命周期是抽象的,其实际行为都是插件来完成的.如mvn package命令表示执行默认生命周期阶段package,这个任务由maven-jar-plugin完成,生命周期和插件协调工做,密不可分.
何为生命周期
一、maven生命周期就是对全部构件过程进行抽象和统一,这个生命周期包含了项目的清理、初始化、编译、测试、打包、验证、部署、站点生成等几乎全部的构建过程,也便是说几乎全部的项目构建,都能映射到这样一个生命周期上.maven的生命周期是抽象的本生不作任何实际的工做,实际的任务由插件来完成,这种思想与模板方法设计模式类似,这样既能保证算法有足够的可扩展性,又能严格控制算法的总体结构.
二、每一个构建步骤均可以绑定一个或者多个插件行为,maven为大多数构建步骤编写并绑定了默认插件,例如针对编译的maven-compiler-plugin,针对测试的mven-surefire-pulgin,虽然大多数时候用户感受不到他们的存在,若是有特殊须要,能够配置插件定制构件行为,甚至本身编写插件.
三套生命周期
一、maven有三套相互独立的生命周期,clean、default和site,clean目的是清理项目,default的目的是构建项目,site目的是创建项目站点.每一个生命周期都是相互独立的,且每一个生命周期都包含一些阶段,用户能够仅仅调用clean生命周期的某个阶段,而不会对其它生命周期产生任何影响,例如,用户调用default生命周期的compile阶段不会触发clean生命周期的任何阶段,反之亦然.
二、clean生命周期包含阶段:pre-clean,clean,post-clean;default生命周期含重要阶段:validate,initialize,process-sources,compile,process-test-sources,test-compile,test,package,install,deploy;site生命周期包含阶段:pre-site,site,post-site,site-deploy.
命令行与生命周期
命令行执行maven任务的最主要方式就是调用maven的生命周期阶段,一个生命周期的阶段是有先后依赖关系的,例以下经常使用命令:
1>mvn clean,该命令调用clean生命周期的clean阶段,实际执行了clean生命周期的pre-clean和clean阶段.
2>mvn test,调用default生命周期的test阶段,实际执行了default生命周期的validate、initialize直到test全部阶段.
3>mvn clean install,调用clean生命周期的clean阶段和default生命周期的install阶段,实际执行了clean生命周期的pre-clean和clean阶段以及default生命周期的validate到install全部阶段,这是一个很好的实践.
插件目标
maven的生命周期和插件相互绑定,用以完成实际的构建任务,实际是生命周期和插件的目标相互绑定,maven的核心分发包只有不到3MB,maven会在须要的时候下载插件.maven有大量的内置绑定,以及基本用不到的自定义绑定,略,知道便可.
插件解析机制
为了方便使用,maven不须要用户提供插件坐标信息,就能够解析获得正确的插件,这是一把双刃剑,与依赖同样,插件构建一样基于坐标存储在maven仓库中,在须要的时候maven会从本地仓库寻找插件,若是不存在,则从远程仓库查找,找到后下载到本地.同依赖同样,maven内置了插件远程仓库配置:
<pluginRepository>
<id>central</id>
<name>Maven plugin</name>
<url>htpp://repo1.maven.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
当maven用到实际项目中时,须要将项目分红不一样的模块,maven的聚合特性能将项目的各个模块聚合在一块儿构建(也就是一次构建两个项目,而不是到两个模块下分别执行mvn命令),而继承特性能帮助抽取各个模块相同的依赖和配置,在简化POM的同时,还能促进各个模块配置的一致性.
聚合
一、为了能一条命令就构件account-email和account-persist两个模块,咱们须要建立一个额外的account-aggregater模块,经过这个模块构建整个项目的全部模块,聚合模块仅仅是帮助聚合其它模块的构建工具,它自己并没有实际的内容,account-aggregator自己也是个 Maven项目,它的目录结构和POM以下:
//父子关系
account-aggregator
--pom.xml
--account-email
----src
----pom.xml
--account-persist
----src
----pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-aggregator</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging> pom </packaging>
<name>Account Aggregator</name>
<modules>
<module>account-email</module>
<module>account-persist</module>
</modules>
</project>
上述POM的groupId与其它两个模块同样,版本也同样,artifactId为本身的,packaging必须为pom.modules是聚合的核心配置,这里每一个module的值都是一个当前pom的相对目录.
二、聚合模块和其它模块的目录结构能够是父子关系或者平行关系.
account-aggregator
--pom.xml
account-email
--src
--pom.xml
account-persist
--src
--pom.xml
聚合模块对应的POM为:
<modules>
<module>../account-email</module>
<module>../account-captcha</module>
</modules>
三、测试,聚合模块运行mvn clean install,能够看到maven解析聚合模块的POM,分析要构建的模块,并计算一个反应堆的构建顺序,而后根据这个顺序依次构建各个模块.
继承
一、多模块maven项目还有一个问题,那就是多个模块的POM有不少相同的配置,maven有继承的机制,让咱们抽取重复的配置.
二、在account-aggregator下建立一个名为account-parent的除account-aggregator以外的全部模块的父模块,它的POM以下:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Maven Account-Parent Project</name>
</project>
这个POM使用了和其它模块一致的groupId和version,artifactId为本身的,它的packaging也必须为pom,因为它只是为了帮助消除重复配置,自己也没有实际内容,有了父模块,account-email的POM修改以下:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>//下面前三个元素指定父模块坐标
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../account-parent/pom.xml</relativePath>
</parent>
<artifactId>account-email</artifactId>
<name>Maven Account-Email Project</name>
<dependencies> ... </dependencies>
<build>
<plugins> ... </plugins>
</build>
</project>
这个POM没有声明groupId和version,实际是从父模块继承了这两个元素,这就消除了一些重复的配置,同理account-persist也这么配置,最后还须要将account-parent加入到account-aggregator:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-aggregator</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging> pom </packaging>
<name>Account Aggregator</name>
<modules>
<module>account-parent</module>
<module>account-email</module>
<module>account-persist</module>
</modules>
</project>
三、除了上面groupId和version能够被继承,依赖也是能够被继承的,两个子模块中都有的spring,junit的依赖等,能够将这些放到父模块中,简化配置,可是有个问题,如今的这两个模块是须要spring这些依赖的,可是之后新加的子模块就不必定须要这个依赖,那也让它强制加这些依赖是不合理的,Maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性,在dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它可以约束dependencies下的依赖使用,如在account-parent中加入dependencyManagement配置:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Maven Account-Parent Project</name>
<properties>
<springframework.version>2.5.6</springframework.version>
<junit.version>4.10</junit.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
继承了dependencyManagement的account-email的POM:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>account-email</artifactId>
<name>Maven Account-Email Project</name>
<properties>
<javax.mail.version>1.4.1</javax.mail.version>
<greenmail.version>1.3.1b</greenmail.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!--非继承的,本身特有的 -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>${javax.mail.version}</version>
</dependency>
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<version>${greenmail.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
上述POM中的依赖配置只有groupId和artifactI的,省去了version,junit还省去了scope,彷佛没有减小太多的配置,但仍是强烈建议这么作,dependencyManagement中统一项目依赖的版本,这样不会发生多个子模块使用依赖版本不一致的状况,下降依赖冲突的记概率.ps:一、若是子模块不声明依赖的使用,则dependencyManagement中声明的依赖也不会引入.二、<scope>import<scope> 略.
四、相似的maven也提供了pluginManagement元素管理插件,该元素中配置的依赖不会形成实际的插件调用行为,当子模块POM中配置了真正的plugin元素,而且其groupId和artifactId与pluginManagement中配置的插件一致时,pluginManagement的配置才会被继承到子模块,以下:
<build>
<!-- 插件 -->
<pluginManagement>
<plugins>
<!-- 支持java 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<!-- 使用UTF-8编码处理资源文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
继承了pluginManagement后的插件子模块配置:
<build>
<plugins>
<!-- 继承父pom -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
</plugins>
</build>
能够将全部用到的插件的版本在父模块中的pluginManagement中声明,子模块使用插件时再也不配置版本信息,这么作能够统一项目的插件版本,避免插件不一致或者不稳定问题,更易于维护.
五、聚合和继承的关系
实际项目中,一个POM可能既是聚合POM又是父POM,这么作是为了方便,例将account-aggregator和account-parent合并一个,以下:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Account-Parent</name>
<modules>
<module>account-email</module>
<module>account-persist</module>
<module>account-captcha</module>
<module>account-service</module>
<module>account-web</module>
</modules>
<!-- Maven属性 -->
<properties>
<springframework.version>2.5.6</springframework.version>
<junit.version>4.10</junit.version>
</properties>
<!-- 依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<!-- 插件 -->
<pluginManagement>
<plugins>
<!-- 支持java 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<!-- 使用UTF-8编码处理资源文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
六、反应堆
1>对于多模块maven项目中,反应堆是指全部模块组成的一个构建结构,反应堆包含了各模块间的继承和依赖关系,从而能自动计算出合理的模块构建顺序.
2>反应堆的构建顺序,构建account-aggregator->account-parent->account-email->account-persist.
3>裁剪反应堆,略.