目录

聚合

重点:

继承

注意:

聚合与继承的关系区别 :

共同点 :

Maven可继承的POM 元素

依赖管理

import依赖范围

插件管理

约定由于配置

反应堆

反应堆的构建顺序

裁剪反应堆


聚合

假设项目【用户注册服务】包含模块:account-email和 account-persist。我们需要进行全部构建,而不是在每个模块目录下都执行mvn命令进行构建。maven聚合(多模块)特性就可以满足此需求。

为了能够使用一条命令就能构建 account-email和 account-persist两个模块,我们需要建立一个额外的名为 account-aggregator的模块,然后通过该模块构建整个项目的所有模块。 account-aggregator本身也是个 Maven项目,它的 POM如下:

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

重点:

  • packaging必须为pom
  • module的值是一个以当前POM为主目录的相对路径

继承

可声明父POM供子 POM继承

父模块POM如下:(packaging为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>Account Parent</name>
</project>  

子模块声明继承如下:

<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>Account Email</name>  ...
</project>  

最后,同样还需要把 account-parent加入到聚合模块account-aggregator中。聚合的 POM如下:

<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>  <module>account-parent</module>  </modules>
</project>  

注意:

  • 子模块没有声明groupId和version, 这两个属性继承至父模块。但如果子模块有不同与父模块的 groupId、version ,也可指定;
  • 不应该继承artifactId,如果groupId ,version,artifactId 完全继承的话会造成坐标冲突;另外即使使用不同的 groupId或version,同样的 artifactId也容易产生混淆。
  • 使用继承后 parent也必须像自模块一样加入到聚合模块中。也就是在在聚合模块的 pom中加入<module>account-parent</module>

聚合与继承的关系
区别

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

共同点

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

Maven可继承的POM 元素

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

依赖管理

Maven提供的dependencyManagement元素既能让子模块继承到父摸块的依赖配置,又能保证子模块依赖使用的灵活性。在dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它能够约束dependencies下的依赖使用。例如,可以在account-parent中加入:

<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><junit.version>4.7</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></dependencies>
</dependencyManagement>

这段配置是会被继承的,如在account-email中

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></dependency>
</dependencies>

这样做的好处:统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,才能保证测试的和发布的是相同的成果,因此,在顶层pom中定义共同的依赖关系。同时可以避免在每个使用的子项目中都声明一个版本号,这样想升级或者切换到另一个版本时,只需要在父类容器里更新,不需要任何一个子项目的修改;如果某个子项目需要另外一个版本号时,只需要在dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。

import依赖范围

import依赖范围只在dependencyManagement元素下才又效果,使用该范围的依赖通常指向一个POM,作用是将目标POM中的dependencyManagement配置导入并合并到当前POM的dependencyManagement元素当中。

<dependencyManagement>  <dependencies>  <dependency>  <groupId>com.juvenxu.mvnbook.account</groupId><artifactId>account-parent</artifactId><version>1.0-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency>  </dependencies>
</dependencyManagement>  

这里的依赖的type值为pom,import范围依赖由于其特殊性,一般指向打包模块为POM的模块,如果有多个项目,他们使用的依赖版本都是一致的,则就可以定义一个使用dependencyManagement专门管理依赖的POM,然后在各个项目中导入这些依赖管理配置。

插件管理

Maven提供了dependencyManagement元素帮助管理依赖,类似地,Maven也提供了pluginManagement元素帮助管理插件。在该元素中配置的依赖不会造成实际的插件调用行为,当POM中配置了真正的plugin元素,并且其groupld和artifactld与pluginManagement中配置的插件匹配时,pluginManagement的配置才会影响实际的插件行为。

例如maven-source-plugin配置了,将其jar-no-fork目标绑定到了verify生命周期阶段,以生成源码包,如果一个项目有很多模块,并且需要得到所有这些模块的源码包,那么很显然,为所有模块重复类似的插件配置不是最好的方法,这时更好的方法是在父POM中使用pluginManagement配置插件。

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

而子模块需要这样配置:

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

子模块声明使用了maven-source-plugin插件,同时又继承了父模块的pluginManagement配置,两者基于groupId和artifactId匹配合并。如果子模块不需要使用父模块中pluginManagement配置的插件,可以尽管将其忽略,如果子模块需要不同的插件配置,则可以自行配置以覆盖父模块的pluginManagement配置。

有了pluginManagement元素account-email和account-persist的POM也能得以简化了,他们都配置了maven-compiler-plugin和maven-resources-plugin,可以将这两个插件的配置移到account-parent的pluginManagement元素中。此时这两个模块可以完全的移除关于maven-compiler-plugin和maven-resources-plugin的配置,但他们仍可以享受这两个插件的服务,前一个插件是开启java 5编译的支持,后一个是使用UTF-8编码处理资源文件,这涉及了Maven很多机制,首先,内置的插件绑定关系将两个插件绑定到了account-email和account-persist的生命周期上,其次,超级POM为这两个插件声明了版本,最后account-parent中的pluginManagement对这两个插件的行为进行了配置。

所以将配置移到父POM的pluginManagement元素中,即使各个模块对于同一插件的具体配置不尽相同,也应当使用父POM的pluginManagement元素统一声明插件的版本,甚至可以要求将所有用到的插件的版本在父POM的pluginManagement元素中声明,子模块使用插件时不配置版本信息,可以统一插件的版本。

约定由于配置

这是Maven最核心的设计理念之一,约定可以减少配置,在Ant中需要做的就是清除构建目录,编译代码,复制依赖至目标目录。最后打包,这是构建最基本的事情,不过此时还是需要写很多的XML配置,源码什么,编译目标和分发目录时什么等等,用户还需要记住各种Ant任务命令,如delete,mkdir,javac和jar,同样是事情,Maven只需要一个最简单的POM

<project>
<modelVersion> 4.0.0</modelVersion>
<groupId>com.juvenxu-mvnbook</groupId>
<artifactId>my-project</artifactId>
<version>1.0</version>
</project>

同时为了获得这样简洁的配置,用户需要付出一定的代价,那就是遵循Maven的约定,Maven会假设用户的项目是这样的:

源码目录src/main/java
    编译输出目录为target/classes/
    打包方式为jar,
    包输出目录为target/

遵循约定虽然会损失一定的灵活性,用户不能随便安排目录,但是却能减少配置,如果没有约定,则10个项目可能使用10种不同的项目目录结构,而有了Maven的约定大家都知道什么目录放什么地方。此外,Ant的自定义目录名称不同,Maven则在命令行暴露的用户接口是统一的,例如mvn clean install这样的命令可以用来构建几乎任何的Maven项目。

如果不想要遵守约定,但是个性往往意味着牺牲通用性,意味着增加无谓的复杂度,例如Maven允许使用你自定义源码目录。

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juvenxu.mvnbook</groupId>
<artifactId>my-project</artifactId>
<version>1.0</version>
<build>
<sourceDirectory>src/java</sourceDirectory>
</build>

此时源码目录就成了src/java了,往往造成交流问题,除非你在处理遗留代码,并且没有办法更改原来的目录结构,此时只能让Maven妥协了。

前面多次提到的超级POM,任何一个Maven项目都隐式的继承自该POM,这有点类似java类隐式继承与Object类,因此大量超级POM的配置都会被所有Maven项目继承,这些配置就成为Maven所提倡的约定。

对于Maven3,超级POM在文件$MAVEN_HOME/lib/maven-model-builder-X.X.X.jar中的org.apache/maven/model/pom-4.0.0.xml路径下,超级POM的内容如下:

  <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定义了仓库和插件仓库,两者的地址都是中央仓库http://repol.maven.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><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.5.3</version></plugin></plugins></pluginManagement></build>

这里依次定义了项目的主输出目录,主代码输出目录等等各个参数设定

反应堆

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

反应堆的构建顺序

将account-aggregator包含

<module>account-email</module>
<module>account-persist</module>
<module>account-parent</module>

构建输出:

上述可以看出反应堆,依次是aggregator,parent,email,persist,结果中看到parent跑到了email之前,这是因为考虑到了继承和依赖关系,因为email和persist都依赖于parent,所有parent就必须先于另外两个模块构建,如果出现A依赖于B,而B也依赖于A时,Maven就会报错。

裁剪反应堆

用户想要仅仅构建完整反应堆中的某些个模块,Maven提供很多的命令行选项支持裁剪反应堆,输入mvn -h可以看到这些选项:

-am,--also-make(同时构建所列模块的依赖模块),
-amd, -also-make-dependents(同时构建依赖于所列模块的模块)
-pl, --projects<arg>(构建指定的模块,模块间用逗号分隔)
-rf -resume-from<arg>(从指定的模块回复反应堆)

默认情况从account-aggregator执行 mvn clean install

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

mvn clean install -pl account-email,account-persist

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

mvn clean install -pl account-email -am。

使用-amd选项可以同时构建依赖于所列模块的模块。account-email,account-persist都依赖于account-parent

mvn clean install -pl account-parent -amd

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

mvn clean install -rf account-email

完整的反应堆构建顺序中,account-email位于第三,之后只有account-persist,因此只会得到email和persist的反应堆

最有在pl -am, pl-amd的基础上,还能应用-rf参数,以对裁剪后的反应堆再次裁剪

mvn clean install -pl account-parent -amd -rf account-email

该命令中的-pl 和- amd参数会裁剪一个account-parent,account-email和account-persist的反应堆,在此基础上,-rf参数指定从account-email参数构建,因此会得到如下反应堆 email和persist:

Maven(3)--聚合与继承相关推荐

  1. maven的聚合和继承详解(2021版)

    前言:日常开发中,两处常见的项目开发场景:多模块项目或者Springboot项目,都会用到Maven的聚合和继承,本篇博客就针对maven这两个技术点进行总结整理,希望能对你有所帮助! 在进入正题之前 ...

  2. Maven之聚合与继承

    Maven之坐标和依赖_jerry_dyy的博客-CSDN博客 Maven之仓库_jerry_dyy的博客-CSDN博客 Maven之聚合与继承_jerry_dyy的博客-CSDN博客 Maven之生 ...

  3. Maven的聚合与继承

    (尊重劳动成果,转载请注明出处:https://blog.csdn.net/qq_25827845/article/details/83867717冷血之心的博客) 关注微信公众号(文强的技术小屋), ...

  4. maven依赖,聚合和继承

    一 依赖 为什么要依赖呢?按照MVC分层思想分为dao,service和controller层,如果将这三层分为三个模块,那么service层要调用(既依赖)dao层代码,如下图 user-servi ...

  5. Maven的聚合和继承(六)

    我们使用Maven应用到实际项目的时候,需要将项目分成不同的模块.这个时候,Maven的聚合特性能够把项目的各个模块聚合在一起构件,而Maven的继承特性则能帮助抽取各模块相同的依赖和插件等配置.在简 ...

  6. Maven学习总结(五)——聚合与继承

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(五)--聚合与继承 一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1. ...

  7. Maven详解之聚合与继承

    Maven详解之聚合与继承 说到聚合与继承我们都很熟悉,maven同样也具备这样的设计原则,下面我们来看一下Maven的pom如何进行聚合与继承的配置实现. 一.为什么要聚合? 随着技术的飞速发展和各 ...

  8. Maven学习总结(5)——聚合与继承

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(五)--聚合与继承 一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1. ...

  9. 6.Maven聚合和继承,相关案例配置

     1有时候一个项目中有很多个模块,要想各个模块之间影响较小,可以将每个模块拿出来作为一个项目模块,对每个项目模块进行独立的开发. 2在这些过程中会遇到关于聚合和继承的问题. 3何为聚合? A如果我 ...

  10. java继承eclipse_Java-Maven(七):Eclipse中Maven依赖、聚合、继承特性

    之前通过学习了解,maven集成到eclipse中的如何创建项目,以及maven命令插件在eclipse中安装后的用法.那么接下来我们将会学习一些maven在项目中的一些特性,及如何使用. Maven ...

最新文章

  1. python手机版下载3.7.3-Python 3.7.0 来了!
  2. Interview:算法岗位面试—上海某科技公司算法岗位(偏AI算法,国企)技术面试之BN层的认知、BP的推导、GD优化的几种改进等
  3. 基本SQL命令-您应该知道的数据库查询和语句列表
  4. A8U推一键上面洗车APP软件
  5. jpa mysql脚本迁移_Spring Boot 数据库迁移:概述
  6. 威胁情报基础:爬取、行走、分析
  7. BestCoder 2nd Anniversary 1004Hdu 5721 Palace
  8. ssh远程访问失败 Centos7
  9. Git下修改提交的author和email信息
  10. 非关系型数据库和关系型数据库区别(转载)
  11. 数据结构 第二章 线性表
  12. Python语音基础操作--5.4小波分解
  13. 如何让搜狗快速收录网站的技巧和方法
  14. 银河英雄传说旗舰名称考证—帝国军
  15. 面向数据中心,浪潮存储双剑出鞘
  16. mysql升级8.0后,项目遇到的坑
  17. 这个地方沸腾,高手争雄,至尊大决战,从天上杀到地下,又从地上打到云霄上!
  18. 三维空间中,向量在另外一个向量或者面上的投影
  19. 基于HTML+JavaScript+CSS计算机实验室预约管理系统网页设计 文档+html源码
  20. ARM汇编语言编程入门实践

热门文章

  1. 学习 jQuery下拉框,单选框,多选框整理
  2. 【JMS】JMS详解
  3. 基于canvas的图片压缩函数实现
  4. vim 粘贴代码格式
  5. wordpress中非插件统计文章浏览次数
  6. nginx中文件路径表示方法
  7. 那些年的那些事CISC和RISC发展中的纠缠
  8. smarty+php+ajax 简单无刷新分页
  9. 十步让你成为一名优秀的 Web开发人员
  10. 如何在网页中动态为模版页的Body添加属性