Maven 聚合和继承

1. 聚合

2. 继承

<parent>
<groupId>org.apache.karaf.demos</groupId>
<artifactId>demos</artifactId>
<version>4.1.5</version>
<relativePath>../pom.xml</relativePath>
</parent>

正确设置 relativepath 非常重要。考虑这样一个情况,开发团队的新成员从源码库签出一个包含父子模块关系的 Maven 项目。由于只关心其中的某一个子模块,它就直接到该模块的目录下执行构建,这个时候,父模块是没有被安装到本地仓库的,因此如果子模块没有设置正确的的 relativepath, Maven 将无法找到父 POM,这将直接导致构建失败。如果 Maven 能够根据 relativepath 找到父 POM,它就不需要再去检査本地仓库。

2.1 可继承的 POM 元素

groupId 和 version 是可以被继承的,那么还有哪些 POM 元素可以被继承呢?以下是一个完整的列表,并附带了简单的说明:

  1. groupId 项目组ID,项目坐标的核心元素
  2. version 项目版本,项目坐标的核心元素
  3. description 项目的描述信息
  4. organization 项目的组织信息。
  5. inceptionYear 项目的创始年份。
  6. url 项目的URL地址。
  7. developers 项目的开发者信息。
  8. contributors 项目的贡献者信息。
  9. distributionManagement 项目的部署配置。
  10. issueManagement 项目的缺陷跟踪系统信息
  11. ciManagement 项目的持续集成系统信息。
  12. scm 项目的版本控制系统信息。
  13. mailinglists 项目的邮件列表信息
  14. properties 自定义的 Maven 属性。
  15. dependencies 项目的依赖配置。
  16. dependencyManagement 项目的依赖管理配置。
  17. repositories 项目的仓库配置。
  18. build 包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等。
  19. reporting 包括项目的报告输出目录配置、报告插件配置等。

2.2 依赖管理

<dependencyManagement>
</dependencyManagement>

2.3 插件管理

<build>
<pluginManagement>
</pluginManagement>
</build>

2.4 聚合与继承的关系

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

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

如果非要说这两个特性的共同点,那么可以看到,聚合 POM 与继承关系中的父 POM 的 packaging 都必须是 pmn,同时,聚合模块与继承关系中的父模块除了 POM 之外都没有实际的内容,如图1 所示

图6.1 聚合关系与继承关系的比较

3. 约定优于配置

Maven 提倡“约定优于配置”(Convention Over Configuration),这是 Maven 最核心的设计理念之一。

那么为什么要使用约定而不是自己更灵活的配置呢?原因之一是,使用约定可以大量减少配置。Maven 只需要一个最简单的 POM 就可以搞定。

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.karaf.demos</groupId>
<artifactId>org.apache.karaf.demos.branding.shell</artifactId>
<version>4.1.5</version>
</project>

这段配置简单得令人惊奇,但为了获得这样简洁的配置,用户是需要付出一定的代价的,那就是遵循 Maven 的的约定。Maven 会假设用户的项目是这样的:

  1. 源码目录为 src/main/java/
  2. 编译输出日录为 targel/classes
  3. 打包方式为 jar 包
  4. 输出目录为 target/

遵循约定虽然损失了一定的灵活性,用户不能随意安排目录结构,但是却能减少配置。更重要的是,遵循约定能够帮助用户遵守构建标准。

也许这时候有读者会问,如果我不想遵守约定该怎么办?这时,请首先问自己三遍,你真的需要这么做吗?如果仅仅是因为喜好,就不要要个性,个性往往意味着辆牲通用性,意味着增加无谓的复杂度:例如, Maven 允许你自定义源码目录:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.karaf.demos</groupId>
<artifactId>org.apache.karaf.demos.branding.shell</artifactId>
<version>4.1.5</version>
<build>
<sourceDirectory>src/java</sourceDirectory>
</build>
</project>

该例中源码目录就成了 src/java 而不是默认的 src/main/java。但这往往会造成交流问题,习惯 Maven 的人会奇怪,源代码去哪里了?当这种自定义大量存在的时候,交流成本就会大大提高。只有在一些特殊的情况下,这种自定义配置的方式才应该被正确使用以解决实际问题。例如你在处理遗留代码,并且没有办法更改原来的目录结构,这个时候就只能让 Maven 妥协。

本书曾多次提到超级 POM,任何一个 Maven 项目都隐式地继承自该 POM,这有点类似于任何一个 Java 类都隐式地继承于 Object 类。서此,大量超级 POM 的配置都会被所有 Maven 项目继承,这些配置也就成为了 Maven 所提倡的约定。对于 Maven3 超级 POM 在在文件 $MAVEN_HOME/lib/maven-model-builder-3.5.0.jar 中的 org/apache/maven/model/pom-4.0.0.xml 路径下。

<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories> <pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>

首先超级 POM 定义了仓库及插件仓库,两者的地址都为中央仓库 htp://repo. mavel.org/ maven2,并且都关闭了 SNAPSHOT 的支持。这也就解释了为什么 Maven 默认就可以按需要从中央仓库下载构件。

<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 项目结构的约定。紧接着超级 POM 为核心插件设定版本。

<pluginManagement>
<!-- NOTE: These plugins will be removed from future versions of the super POM -->
<!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.3.2</version>
</plugin>
</plugins>
</pluginManagement>

可以看到,超级 POM 实际上很简单,但从这个 POM 我们就能够知晓 Maven 约定的由来,不仅理解了什么是约定,为什么要遵循约定,还能明白约定是如何实现的。

4. 反应堆

在一个多模块的 Maven 项目中,反应堆(Reactor)是指所有模块组成的一个构建结构。对于单模块的项目,反应堆就是该模块本身,但对于多模块项目来说,反应堆就包含了各模块之间继承与依赖的关系,从而能够自动计算出模块构建顺序。

4.1 反应雄的构建序

实际的构建顺序是这样形成的: Maven 按序读取 POM,如果该 POM 没有依赖模块,那么就构建该模块,否则就先构建其依赖模块,如果该依赖还依赖于其他模块,则进一步先构建依赖的依赖。

4.2 裁剪反应雄

一般来说,用户会选择构建整个项目或者选择构建单个模块,但有些时候,用户会想要仅仅构建完整反应堆中的某些个模块。换句话说,用户需要实时地裁剪反应堆。

Maven 提供很多的命令行选项支持裁剪反应堆,输入 mvn -h 可以看到这些选项:

  1. -am --also-make 同时构建所列模块的依赖模块口

  2. -amd --also-make-dependents 同时构建依赖于所列模块的模块

  3. -pl --projects 构建指定的模块,模块间用逗号分隔口

  4. -rf --resume-from 从指定的模块回复反应堆

    使用-pl选项指定构建某几个模块

    mvn clean install -pl account-email account-persist

    使用 -amd 选项可以同时构建依赖于所列模块的模块

    mvn clean install -pl account-parent -amd

    使用-rf选项可以在完整的反应堆构建顺序基础上指定从哪个模块开始构建

    mvn clean install - rf account-email

06 Maven 聚合和继承的更多相关文章

  1. maven聚合与继承笔记

    maven聚合 聚合的目的是为了快速构建项目,当我们有几个maven模块,想要一次性构建,而不是到每个模块下面去执行maven命令,这时候就需要使用maven聚合(或者称为多模块). 使用聚合的时候, ...

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

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

  3. Maven——聚合与继承

    原文:http://www.cnblogs.com/xdp-gacl/p/4058008.html 一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1.聚合配置代码 ...

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

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

  5. 笔记:Maven 聚合和继承

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

  6. maven课程 项目管理利器-maven 3-10 maven聚合和继承 4星

    本节主要讲了以下内容: 1 maven聚合 2 maven继承 1 maven聚合 <!-- 聚合特有标签 --> <groupId>com.hongxing</grou ...

  7. maven学习(十二)——maven聚合与继承实战

    聚合与继承实战 创建四个Maven项目,如下图所示:

  8. Maven 教程(14)— Maven聚合与继承

    原文地址:https://blog.csdn.net/liupeifeng3514/article/details/79553011 1.Maven聚合 我们在平时的开发中,项目往往会被划分为好几个模 ...

  9. Java开发学习(三十)----Maven聚合和继承解析

    一.聚合 分模块开发后,需要将这四个项目都安装到本地仓库,目前我们只能通过项目Maven面板的install来安装,并且需要安装四个,如果我们的项目足够多,那么一个个安装起来还是比较麻烦的 如果四个项 ...

随机推荐

  1. django中使用Form组件

    内容: 1.Form组件介绍 2.Form组件常用字段 3.Form组件校验功能 4.Form组件内置正则校验 参考:https://www.cnblogs.com/liwenzhou/p/87478 ...

  2. python编程之禅

    在python界面输入 import this >>> import this The Zen of Python, by Tim Peters Beautiful is bette ...

  3. linux运维工程师工作中的一些常见问题解决方法

    http://blog.sina.com.cn/s/blog_b9fe247a0101anoe.html 1.shell脚本死活不执行 问题:某天研发某同事找我说帮他看看他写的shell脚本,死活不执 ...

  4. 微信公众平台开发者认证,node

    纯属分享 app.js var express = require('express'); var path = require('path'); var app = express(); ; var ...

  5. eclipse包层级显示和工作空间显示

    本文两件事:设置包层级显示.设置工程的工作空间显示 一.各package包分层显示 平铺显示,实在不方便开发!也不方便查看工程包的层级结构,如下: 更换成层级显示: 二.工作空间显示 包用来区分类,工 ...

  6. Java 8 日期时间API

    Java 8一个新增的重要特性就是引入了新的时间和日期API,它们被包含在java.time包中.借助新的时间和日期API可以以更简洁的方法处理时间和日期; 在介绍本篇文章内容之前,我们先来讨论Jav ...

  7. python 1 面向对象基础知识

    1.编码范式 编程  是程序员用特定的 语法+数据结构+算法 组成的代码来告诉计算机如何执行任务的过程 如果把编程比作习武,编程方式就是武林中的各种流派,而在编程的世界里面最常见的两大流派是:面向过程 ...

  8. 使用JavaScript的XMLHttpRequest发送POST、GET请求以及接收返回值

    使用XMLHttpRequest对象分为4部完成: 1.创建XMLHttpRequest组建 2.设置回调函数 3.初始化XMLHttpRequest组建 4.发送请求 实例代码: [javascri ...

  9. 主流JS库一览

    主流JS库一览 标签: prototypedojomootoolsprototypejsjqueryjavascript 2009-10-14 22:52 19936人阅读 评论(2) 收藏 举报   ...

  10. 关于HTTP协议及SOCKET通信

    一.HTTP 1.报文结构 HTTP:超文本传输协议,报文分为请求报文和响应报文. 2.端口(tomcat端口) http在熟知的80端口使用TCP的服务:tomcat的默认端口是8080 3.状态码 ...