为了减少重复代码的编写,我们需要创建POM的父子结构,然后在POM中申明一些配置供子POM继承,以实现“一处申明,多处使用的”目的。以之前的模块中的结构为基础,在account-aggregator下创建一个account-parent的子目录,然后在该子目录下创建除account-aggregator模块之外的模块的父模块。为此在该子目录下创建一个pom.xml文件如下:

<?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.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Account Parent</name>
</project>

需要注意的是它的packaging的值必须为pom,这一点与模块聚合一样,作为负模块的POM,其打包类型也必须为pom。由于父模块只是为了消除配置的重复,因此也就不需要src/main/java等目录了。

有了父模块就让其他子模块来继承它,修改account-email的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>
<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>Account Email</name> <dependencies>
......
</dependencies> <build>
<plugins>
......
</plugins>
</build> </project>

parent下的子元素groupId、artifactId和version指定了父模块的坐标,这三个元素是必须的。元素relativePath表示父模块POM的相对路径。当项目构建时,Maven会首先根据relativePath检查父POM,如果找不到,再从本地仓库查找。relativePath的默认值是../pom.xml,也就是说,Maven默认父POM在上一层目录下。

这个更新过的POM文件并没为account-email设置artifactId和version,实际上这个子模块隐式的从父模块继承了这两个元素。如果子模块中遇到与父模块中不一样的artifactId、version这个时候应该在子模块显示声明。

最后还要把父模块加入到聚合模块account-aggregator中如下:

<?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.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>

此时的目录结构是account-parent、account-email、account-persist在同一级目录,account-aggregator为三个目录的父目录。

可继承的POM元素如下:

  • groupId:项目组ID,项目坐标的核心元素
  • version:项目版本,项目坐标的核心因素
  • description:项目的描述信息
  • organization:项目的组织信息
  • inceptionYear:项目的创始年份
  • url:项目的URL地址
  • developers:项目的开发者信息
  • contributors:项目的贡献者信息
  • distributionManagement:项目的部署配置
  • issueManagement:项目的缺陷跟踪系统信息
  • ciManagement:项目的持续集成系统信息
  • scm:项目的版本控制系统西溪
  • malilingLists:项目的邮件列表信息
  • properties:自定义的Maven属性
  • dependencies:项目的依赖配置
  • dependencyManagement:项目的依赖管理配置
  • repositories:项目的仓库配置
  • build:包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
  • reporting:包括项目的报告输出目录配置、报告插件配置等

  依赖管理

  因为dependencies元素也是可继承的,因此我们可以把公共的jar放到父模块account-parent中,比如org.springframework:spring-core:2.5.6在account-email,account-persist模块中都会用到,因此可以将这个依赖配置放到父模块中,两个子模块就能移除这些依赖从而简化配置。

  上述做法是可行的,但是存在问题。因为所有的子模块都会继承以上父模块的依赖项,不管子模块是否真的需要此依赖项。这样相当于子模块失去了这些依赖项继承的选择权。假设后面加了模块acount-util与springframework没有半毛钱关系,让他依赖spring的依赖项显然是不合理的。

  为此Maven提供了dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖的使用灵活性。在dependencyManagement元素下的依赖声明不会引入到实际的依赖,不过它能约束dependencies下的依赖使用。

<?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.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Account Parent</name>
<properties>
<springframework.version>2.5.6</springframework.version>
</properties> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework </groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency> ...... </dependencies>
</dependencyManagement>
</project>

  这里使用了dependencyManagement声明的依赖既不会给account-parent引入依赖项,也不会给他的子模块引入依赖,不过这段配置会被继承。现在修改account-email的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>
<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>Account Email</name> <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency> ...... </dependencies> <build>
<plugins>
......
</plugins>
</build> </project>

  上面的配置较原来简单了一些,只配置了groupId和artifactId,省去了version,如果父模块配置了依赖的scope也是可以省略的。这些信息可以省略是因为account-email继承了account-parent中的dependencyManagement配置,完整的依赖声明已经包含在父POM中了,子模块只需简单的配置groupId和artifactId。

  使用这种以来管理机制虽然不能减少太多的配置项,但是经过别人实践后强烈推荐的方法。如果子模块不声明依赖的使用,即使该依赖已经在父POM文件dependencyManagement中声明了,也不会产生任何实际的效果。

插架管理

  Maven提供了dependencyManagement元素帮助管理依赖,类似的,Maven也提供了pluginManagement元素帮助管理插件。当子模块POM中配置了plugin,并且groupId和artifactId与pluginManagement中的配置的插件匹配时,pluginManagement的配置才会真正影响实际插件的行为。

  父POM文件:

  <build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>

  在子模块继承pluginManagement后的插件配置

  <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
</plugins>
</build>

聚合与继承的关系

区别 :

1.对于聚合模块来说,它知道有哪些被聚合的模块,但那些被聚合的模块不知道这个聚合模块的存在。

2.对于继承关系的父 POM来说,它不知道有哪些子模块继承与它,但那些子模块都必须知道自己的父 POM是什么。

 

共同点 :

1.聚合 POM与继承关系中的父POM的 packaging都是pom

2.聚合模块与继承关系中的父模块除了 POM之外都没有实际的内容。

 
现有的实际项目往往是一个POM既是聚合POM又是父POM,这么做主要是为了方便。
 
反应堆:
  在一个多模块的Maven项目中,反应堆是指所有模块组成的一个构建结构。反应堆包含了各个模块之间的继承与依赖关系,从而能够自动计算出合理的模块构建顺序。
<modules>
<module>account-email</module>
<module>account-persist</module>
<module>account-parent</module>
</modules>

  实际的构建顺序为: ~parent, ~email, ~persist。

  可见构建的顺序并不是声明的顺序。

  该例中account-email和account-persist都依赖于account-parent,那么account-parent就必须在另外两个模块之前构建。实际的构建顺序是这样的:Maven按声明顺序读取POM,如果POM没有依赖模块,那么久构建该模块,否则就先构建其依赖的模块。,如果依赖的模块还依赖于其他模块,则进一步构建依赖的依赖。

  模块之间的关系将反应堆构成一个有向非循环图,各个模块是该图的节点,依赖关系构成又向边,这个图不允许出现循环,因此当出现A依赖于B,B又依赖于A的情况时Maven就会报错。

裁剪反应堆:

mvn -h可以看到这样一些选项:

Options:
-am,--also-make If project list is specified, also
build projects required by the
list
-amd,--also-make-dependents If project list is specified, also
-pl,--projects <arg> Build specified reactor projects
instead of all projects. A project
can be specified by
[groupId]:artifactId or by its
relative path.
-rf,--resume-from <arg> Resume reactor from specified
project

  有的时候因为工程巨大,模块很多,只想构建指定的模块,这时候就会用到反应堆裁剪。

-pl 构建指定模块
mvn clean install -pl accouont-email,account-persist后会得到如下几个模块:~email和~persist。

-am 选项可以同时构建所列模块的依赖模块。
当执行mvn clean install -pl account-email -am 后会得到如下几个模块:~parent和~email。

-amd 选项可以同时构建依赖于所列模块的模块。
mvn clean install -pl account-parent -amd 后会得到如下模块:~parent、~email和~persist。

-rf 选项可以在完整的反应堆构建顺序基础上,指定从哪个模块开始构建。
mvn clean install -rf account-email ,由于~email位于第三,它之后有~persist,因此会得到如下输出模块:~email和~persist。

在-pl -am或者-pl -amd的基础上,还能应用-rf参数,以对裁剪后的反应堆再次裁剪。
mvn clean install -pl account-parent -amd -rf account-email
其中,-pl 和 -amd参数会得到:~parent, ~email和~persist模块,在此基础上 -rf参数制定从~email开始构建,于是会得到:~email和~persist。

Maven POM元素继承的更多相关文章

  1. Maven pom.xml 元素配置说明(一)

    部分来源: Maven中 dependencies 节点和 dependencyManagement 节点的区别 dependencies与dependencyManagement的区别 maven ...

  2. Maven pom.xml中的元素modules、parent、properties以及import

    前言 项目中用到了maven,而且用到的内容不像利用maven/eclipse搭建ssm(spring+spring mvc+mybatis)用的那么简单:maven的核心是pom.xml,那么我就它 ...

  3. Maven pom.xml中的元素modules、parent、properties以及import(转)

    前言 项目中用到了maven,而且用到的内容不像利用maven/eclipse搭建ssm(spring+spring mvc+mybatis)用的那么简单:maven的核心是pom.xml,那么我就它 ...

  4. maven pom继承与聚合

    一.POM聚合模块: 在分布式架构,分模块化开发中,每个某块可能都是一个单独的maven项目,能够独立的进行项目构架,当模块比较多时,可以使用maven聚合聚合项目来简化maven构建,一次构建多个项 ...

  5. (十四)Maven聚合与继承

    1.Maven聚合 我们在平时的开发中,项目往往会被划分为好几个模块,比如common公共模块.system系统模块.log日志模块.reports统计模块.monitor监控模块等等.这时我们肯定会 ...

  6. 史上最全的maven pom.xml文件教程详解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  7. Maven POM.xml (转)

    简介 pom.xml文件是Maven进行工作的主要配置文件.在这个文件中我们可以配置Maven项目的groupId.artifactId和version等Maven项目必须的元素:可以配置Maven项 ...

  8. Maven聚合和继承的详细解释

    说到聚合与继承我们都非常熟悉,maven相同也具备这种设计原则.以下我们来看一下Maven的pom怎样进行聚合与继承的配置实现. 一.为什么要聚合? 随着技术的飞速发展和各类用户对软件的要求越来越高. ...

  9. 笔记:Maven 聚合和继承

    聚合模块 我们希望一次构建两个或更多项目,而不是到每个模块的目录下分别执行mvn命令,Maven 聚合这一特性就是为该需求服务的, 为了使用聚合,我们必须创建一个聚合模块,通过该模块与其他项目聚合,并 ...

随机推荐

  1. 用ORM的思想操作XML文档,一个对象就搞定不要太简单。滚蛋吧!XmlDocument、XmlNode、Xml***……

    大家有没有这样的感受,一涉及XML文档操作就得百度一遍.是不是非!常!烦!.各种类型,各种方法,更别提为了找到一个节点多费劲.本来想写个XML操作的工具方法,写了两行一想既然XML文档是有规律的,如果 ...

  2. js入门学习~ 运动应用小例

    要实现的效果如下: 鼠标移入各个小方块,实现对应的效果(变宽,变高,移入透明,移出恢复)~~ (且各运动相互之前不干扰)  主要是练习多个物体的运动框架~~ --------------------- ...

  3. linux umount

    linux umount 提示"device is busy" 终极解决方法 http://www.wisdr.com/news/20120621174117.htm 这里面的方法亲测可用. 小tip ...

  4. pcl计算样点法向并显示

    利用最小二乘法估计样点表面法向,并显示 #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include < ...

  5. Hibernate 中出现表名(XXX) is not mapped 问题

    今天晚上自己试着用Hibernate去搭建一个Web工程,然后去实现一个简单的登录.通过Hibernate?做查询操作的时候总是报出这样的错:users is?not?mapped. 于是乎去检查了下 ...

  6. [LeetCode] Largest BST Subtree 最大的二分搜索子树

    Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest mea ...

  7. [LeetCode] Convert Sorted List to Binary Search Tree 将有序链表转为二叉搜索树

    Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...

  8. Mysql的连接状态

    对应mysql的连接,任何时刻都有一个状态.表示mysql当前正在做什么. command里面的状态: sleep:线程正在等待客户发送新的请求. query:正在执行查询或者正在将结果发送客户端 这 ...

  9. javascript-- test() 匹配正则 与 逻辑运算符 “!”

    在使用正则表达式验证"时分秒"的时候遇到了一个问题,因为业务需求,需要提供两个input 给用户输入开始时间和结束时间. js 代码: var regtime=/^([0-1]?[ ...

  10. 几个MQTT的知识点

    开始正文前需要感谢一下网友“小龙”和emqtt.io群里的网友们的帮助,本人刚刚开始使用MQTT有很多不懂的地方,在emqtt.io群里询问解决方法的时候,“小龙”给我详细的讲解了一些MQTT的知识点 ...