在实际项目的使用中,经常会对项目进行模块划分,以下降耦合。如服务接口模块,各业务模块,web模块等。而模块间共享一些相同的依赖,彼此间也紧密联系。此时咱们就能够经过maven的聚合和继承来管理模块。java
好比如今咱们有如下模块:web
模块间的关系是example-web和example-service经过example-api相链接。spring
example-web -> example-api <- example-service
此时咱们能够建立一个聚合模块example-parent,也能够称做父模块。它的pom.xml以下apache
<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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lcifn.maven</groupId> <artifactId>example-parent</artifactId> <version>0.0.1</version> <packaging>pom</packaging> <name>example</name> <modules> <module>example-api</module> <module>example-service</module> <module>example-web</module> </modules> </project>
对于聚合模块来讲,其打包方式packaging的值必须为pom,不然没法构建。通常聚合模块的内容仅是一个pom.xml,它就是帮助聚合其余模块构建的工具。api
而对于子模块来讲,经过继承父pom,将公共的配置统一在父pom中管理,好比依赖的版本以及插件的管理。maven
以example-api为例工具
<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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.lcifn.maven</groupId> <artifactId>example-parent</artifactId> <version>0.0.1</version> </parent> <artifactId>example-api</artifactId> <version>0.0.1</version> </project>
parent标签内的子元素groupId,artifactId和version指定父模块的坐标。对于子模块,父模块的pom中不少元素是能够继承的ui
以上只是列举了经常使用的一些元素插件
实际使用时,聚合模块和父模块每每是同一模块。code
项目中依赖的spring多个组件但愿都是同一版本的,这样能避免因版本问题出现的奇怪错误,能够经过maven的dependencyManagement来管理。在dependencyManagement元素下的依赖声明不会引入实际的依赖,而它能够约束dependencies下的依赖的使用。
在父模块的pom中加入配置
<properties> <spring.version>4.1.6.RELEASE</spring.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> </dependencies> </dependencyManagement>
将经常使用的依赖版本以maven变量提取出来,消除重复,并方便之后升级。
在子模块的pom文件中,只须要配置groupId和artifactId就能得到对应的依赖信息,从而可让多个模块统一使用统一版本的依赖,减小依赖冲突。
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> </dependencies>
maven也提供了pluginManagement元素帮助管理插件,在该元素中配置的依赖不会形成实际的插件调用行为,当子模块的pom中配置了真正的plugin元素,而且groupId和artifactId与pluginManagement中配置的插件匹配时,pluginManagement的配置才会产生真正的影响。
父模块的pom文件,配置maven-source-plugin,将jar-no-fork目标绑定到verify生命周期阶段,生成项目源码包。
<pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>3.0.1</version> <executions> <execution> <id>attach-sources</id> <phase>verify</phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> </plugins> </pluginManagement>
当子模块须要生成源码包时,只须要简单配置
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> </plugin> </plugins>
maven提倡“约定优于配置”,从而能够减小大量的配置。一个项目构建要完成的最基本的事情,包括清除构建目录,建立目录,编译代码,复制依赖至目标目录,最后打包。若是使用ant,须要在配置文件中指定源码目录是什么,编译目标目录是什么,分发目录是什么等等。而使用maven后,用户付出必定的代价来遵照manven的约定,便可用很是简单的pom文件来达到相同的目的。
maven对用户目录的约定以下
这些默认的约定定义在maven的超级pom文件中,任何一个Maven项目都隐式继承该pom,有点相似jave类都继承于Object类。对于maven3,超级pom文件在$MAVEN_HOME$/lib/maven-model-builder-3.3.1.jar
中的org\apache\maven\model\pom-4.0.0.xml。
简单列举下超级pom中对项目结构的定义
<build> <directory>${project.basedir}/target</directory> <outputDirectory>${project.build.directory}/classes</outputDirectory> <finalName>${project.artifactId}-${project.version}</finalName> <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory> <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory> <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory> <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory> <resources> <resource> <directory>${project.basedir}/src/main/resources</directory> </resource> </resources> <testResources> <testResource> <directory>${project.basedir}/src/test/resources</directory> </testResource> </testResources> </build>
在一个多模块的Maven项目中,反应堆(Reactor)指全部模块组成的一个构建结构。对于单模块的项目,反应堆就是模块自身,而对于多模块项目,反应堆就包含了各模块之间继承与依赖的关系,从而可以自动计算合理的模块构建顺序。
上述example-parent的构建顺序就是
模块间的依赖关系会将反应堆构成一个有向非循环图。当出现两个模块相互依赖时,maven会报错。
有些时候,用户会想仅仅构建完整反应堆的某些个模块,即裁剪反应堆。maven提供命令支持裁剪反应堆。
可使用-pl指定构建某几个模块
mvn clean install -pl example-api,example-service
使用-am同时构建所列模块的依赖模块
mvn clean install -pl example-service -am
使用-amd构建依赖于所列模块的模块
mvn clean install -pl example-api -amd
使用-rf在完整反应堆构建顺序基础上指定从哪一个模块开始构建
mvn clean install -rf example-service
在开发过程当中,灵活应用上述参数,能够帮助咱们跳过无须构建的模块,从而加速构建,尤为在项目庞大,模块众多的时候。