Maven 学习总结(三) 之 依赖管理
聚合
为了要一次构建多个项目,而不是到每个模块目录下分别执行mvn命令。maven聚合这一特性就是为该需求服务的。为此我们需要创建一个额外的模块aggregator,
然后通过该模块构建整个项目的所有模块。aggregator本身作为一个maven项目,它必须要有自己的POM,不过,同时作为一个聚合项目,其POM有特殊的地方。
  
上述POM使用了共同的groupId,artifactId为独立的aggregator,packaging为POM. 对于聚合模块来说,其打包方式packaging必须为POM,否则就无法构建。
POM的name字段是为了给项目提供一个更容易阅读的名字,modules是实现聚合的最核心的配置。用户可以通过在一个打包方式为pom的maven项目
中声明任意数量的module元素来实现模块的聚合。这里每个module的值都是一个当前POM的相对目录。
一般来说为了方便快速定位内容,模块所处的目录名称应该与其artifactId一直,不过这不是maven的要求。
aggreagtor的内容仅仅是一个pom.xml文件,它不像其他模块那样有src/main/java、src/test/等目录。聚合模块仅仅是帮助聚合其他模块的构建工具,它本身无实质内容。
关于目录结构还需要注意的是,聚合模块与其他模块的目录结构并非一定要是父子关系还可以是平行的目录关系。
  
如果使用平行目录结构,聚合模块的POM也需要做相应的修改,以指向正确的模块目录:
  
Maven会首先解析聚合模块的POM、分析要构建的模块、并计算出一个反应堆构建顺序,然后根据这个顺序依次构建各个模块。反应堆是所有模块组成的一个构建结构。
继承
可以穿件POM的父子结构,然后在父POM中声明一些配置子POM继承,以实现“一处声明,多处使用”的目的。创建一个名为parent的目录,然后在该子目录下建立一个父模块。在该子目录创建一个pom.xml文件,内容如下:
  
该pom使用了与其他模块一致的groupId和version,packaging为pom,与聚合模块一样,作为父模块的POM,其打包类型必须为PM
父模块只是为了帮助消除配置的重复,将子类的依赖配置配置提取到父模块中。因此它本身不包含除POM之外的项目文件。有了父模块,就需要让其他模块来继承它。
  
上述POM中使用parent元素声明父模块,parent下的子元素groupId、artifactId和version指定了父模块的坐标,这三个元素是必须的。
这三个元素是必须的。元素relativePath表示父模块POM的相对路径。当项目构建时,maven会首先根据relativePath检查父POM,如果找不到,
再从本地仓库查找。relativePath的默认值是../pom.xml.也就是说,父POM在上一层目录下。
将parent加入到聚合模块aggregator:
  
可继承的POM元素
那些元素POM元素可以继承?
groupId : 项目ID,项目坐标的核心元素;
version:项目版本,项目坐标的核心元素;
description:项目描述信息;
  
依赖管理
Maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性。在dependencyManagement元素
下的依赖声明不会引入实际的依赖,不过它能够约束dependencies下的依赖灵活使用。parent中加入这样的dependencyManagement配置:
  
这里使用dependencyManagement声明的依赖既不会给parent引入依赖,也不会给它的子模块引入依赖,不过这段配置是会被继承的
子模块的POM如下:
  
使用这种依赖管理机制似乎不能减少太多的POM配置,不过还是强烈推荐采用这种方法。其主要原因在于父POM使用dependencyManagement
声明依赖能够统一项目范围中依赖的版本,当依赖版本在父POM中声明之后,子模块在使用依赖的时候就无须声明版本,也就不会发生多个子模块使用依赖版本不一致的情况。
这可以帮助降低依赖冲突的几率。 如果子模块不声明依赖的使用,即使该依赖已经在父POM的dependencyManagement中声明了,也不会产生任何实际的效果。
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>
import依赖范围由于其特殊性,一般都是指向打包类型为pom的模块,如果有多个项目,他们使用的依赖版本都是一致的,则就可以定义一个使用dependencyManagement专门管理依赖的POM,
然后在各个项目中导入这些依赖管理配置。
插件管理
Maven也提供了pluginManagement元素帮助管理插件。在该元素中配置的依赖不会造成实际的插件调用行为,当POM中配置了真正的plugin元素,并且其groupId和artifactId与
pluginManagement中配置的插件匹配时,pluginManagement的配置才会影响实际的插件行为。
  
当子模块需要生成源码包的时候,只需要如下的简单配置
<build>
<plugins>
<plugin>
<groupId>org.apache.plugin</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
</plugins>
</build>
子模块声明使用了maven-source-plugin插件,同时又继承了福模块的pluginManagement配置,两者基于groupIdhe artifactId匹配合并之后相当于完整的插件配置。
如果子模块不需要使用福模块中的pluginManagement配置插件,可以尽管将其忽略。如果子模块需要不同的插件配置,则可以自行配置以覆盖父模块的pluginManagement配置。
当项目中的多个模块有同样的插件配置时,应该将配置移到父POM的pluginManagement元素中。即使各个模块对于同一插件的具体配置不尽相同,也应当使用父POM的pluginManagement
元素同一声明插件的版本。甚至可以要求将所有用到的插件的版本在父POM的pluginManagement元素中声明,子模块使用插件时不配置版本信息,这么做可以同一项目的插件版本,
避免亲在的插件不一致或者稳定问题,也易于维护。
聚合与集成的关系
多模块Maven项目中的聚合与继承其实是另两个概念,其目的完全是不同的,前者主要是为了方便快速构建项目,后者主要是为了消除重复配置。
对于聚合模块来说,他不知道有哪些被聚合的模块,但哪些被聚合的模块不知道这个聚合模块的存在。
对于继承关系的父POM来说,它不知道有哪些子模块继承于他,但哪些子模块都知道自己的父POM是什么。
如果非要说这两个特性的共同点,那么可以看到,聚合POM与集成关系中的父POM的packaging都必须是pom,同时,聚合模块与继承关系中的父模块除了POM之外都没有实际的内容。融合使用继承和聚合也没有什么问题。
  
约定由于配置
Maven提倡“约定优于配置”这是maven最核心的设计理念之一。使用约定可以大量减少配置。遵循约定虽然损失了一定的灵活性,用户不能随意安排目录结构,
但是却能减少配置,更重要的是,遵循约定能够帮助用户转手构建标准。Mavne在生命行暴露的用户接口是统一的想mvn clean install
这样的命令可以用来构建几乎任何的mavne项目。任何一个maven项目都隐式地继承自该POM,因此大量超级POM的配置会被所有maven项目集成,
这些配置也就成为了mavne所提倡的约定。
反应堆
在多个模块的maven项目中,反应堆是指所有模块组成的一个构建结构。对于单模块的项目,反映堆就是该模块本身,但对于模块项目来说,
反应堆就包含了各模块之间继承与依赖的关系,从而能够自动计算出合理的模块构建顺序。
反应堆的构建顺序:Maven按序读取pom,如果该POM没有依赖模块,那么久构建该模块,否则就先构建其依赖模块,如果该模块还依赖于其他模块,则进一步先构建依赖的模块。
模块间的依赖关系会讲反映堆构成一个有向非循环图,各个模块是该模块的节点,依赖关系构成有向边,这个图不允许出现循环。
剪裁反应堆:一般来说,用户会选择构建整个项目或者选择构建单个模块,但有时候,用户会想要仅仅构建完整反应堆中的某些歌模块,换句话说,用户需要实时地剪裁反应堆。
  
假设aggregator执行 mvn clean install会得完整的反应堆:
  
使用-pl选项指定构建某几个模块:mvn clean install -pl account-email,account-persist得到反应堆为:
  
使用-am选项可以同时构建所列模块的依赖模块,例如:mvn clean install -pl account-email -am:
  
使用-amd选项可以同时构建依赖于所列模块的模块。mvn clean install -pl account-parent -amd
  
使用-rf 选项可以在完整的反应堆构建顺序基础上制定从哪个模块开始构建,mvn clean install -rf account-email
  
Maven 学习总结(三) 之 依赖管理的更多相关文章
- (转)Maven学习总结(三)——使用Maven构建项目
		
孤傲苍狼 只为成功找方法,不为失败找借口! Maven学习总结(三)——使用Maven构建项目 maven作为一个高度自动化构建工具,本身提供了构建项目的功能,下面就来体验一下使用maven构建项目的 ...
 - 【系列教程1】Gradle入门系列三:依赖管理
		
在现实生活中,要创造一个没有任何外部依赖的应用程序并非不可能,但也是极具挑战的.这也是为什么依赖管理对于每个软件项目都是至关重要的一部分. 这篇教程主要讲述如何使用Gradle管理我们项目的依赖,我们 ...
 - Gradle for Android 第三篇( 依赖管理 )
		
依赖管理 这会是一个系列,所以如果你还没有看我之前的几篇文章,请先查看以下文章: Gradle for Android 第一篇( 从 Gradle 和 AS 开始 ) Gradle for Andro ...
 - 【转载】Gradle for Android 第三篇( 依赖管理 )
		
依赖管理是Gradle最闪耀的地方,最好的情景是,你仅仅只需添加一行代码在你的build文件,Gradle会自动从远程仓库为你下载相关的jar包,并且保证你能够正确使用它们.Gradle甚至可以为你做 ...
 - 【转载】Gradle学习 第八章:依赖管理基础
		
转载地址:http://ask.android-studio.org/?/article/10 This chapter introduces some of the basics of depend ...
 - Maven学习(三) -- 仓库
		
标签(空格分隔): 学习笔记 坐标和依赖时任何一个构件在Maven世界中的逻辑表示方式:而构件的物理表示方式是文件,Maven通过仓库来同意管理这些文件. 任何一个构件都有其唯一的坐标,根据这个坐标可 ...
 - Maven学习(三)
		
maven相关概念 maven坐标 Maven世界拥有大量构建,当我们需要引用依赖包是,需要用一个用来唯一标识去确定唯一的一个构建.如果拥有了统一规范,就可以把查找工作交给机器. 类似于空间找点的坐标 ...
 - Maven(六)之依赖管理
		
前面讲了maven一些关于Maven的简单知识,今天我给大家分享一些Maven的依赖管理.我相信用过maven的人都知道,它很重要的功能就是通过依赖来添加jar包. 让我们领略一下Maven是怎么管理 ...
 - Maven学习(三)maven原理概念详述
		
maven相关概念 maven坐标 Maven世界拥有大量构建,当我们需要引用依赖包是,需要用一个用来唯一标识去确定唯一的一个构建.如果拥有了统一规范,就可以把查找工作交给机器. 类似于空间找点的坐标 ...
 - Maven学习笔记—坐标和依赖
		
Maven的坐标和依赖 1 Maven坐标 1.1 什么是Maven坐标 Maven坐标:世界上任何一组构件都可以使用Maven坐标来唯一标识,Maven坐标的元素包括groupId.artifact ...
 
随机推荐
- 微信小程序自动化测试--接口测试
			
偷得一篇文章: postman测试微信小程序接口---postman https://www.sunzhongwei.com/using-the-postman-test-wechat-mini-ap ...
 - 用一条SQL语句显示所有可能的比赛组合
			
一个叫team的表,里面只有一个字段name,一共有4 条纪录,分别是a.b.c.d,对应四个球队,现在四个球队进行比赛,用一条SQL语句显示所有可能的比赛组合. select * from team ...
 - 调用远程主机上的 RMI 服务时抛出 java.rmi.ConnectException: Connection refused to host: 127.0.0.1 异常原因及解决方案
			
最近使用 jmx 遇到一个问题,client/server 同在一台机器上,jmx client能够成功连接 server,如果把 server 移植到另一台机器上192.168.134.128,抛出 ...
 - Interrupt中断线程注意点
			
首先我们要明确,线程中断并不会使线程立即退出,而是发送一个通知,告知目标线程你该退出了,但是后面如何处理,则完全有目标线程自行决定. 这就是和stop()不一样的地方,stop执行后线程会立即终止,这 ...
 - HBase实践案例:车联网监控系统
			
项目背景 本项目为车联网监控系统,系统由车载硬件设备.云服务端构成.车载硬件设备会定时采集车辆的各种状态信息,并通过移动网络上传到服务器端.服务器端接收到硬件设备发送的数据首先需要将数据进行解析,校验 ...
 - 在Linux命令行中以图形化窗口打开文件夹
			
Linux 系统中也有类似的命令.Ubuntu 发行版的命令行中,我们可以使用 nautilus 命令来打开指定目录的图形化窗口界面.类似下面命令这样使用: nautilus /home/testPr ...
 - day4-python基础-数据类型
			
今日份小技巧 a =3 b=4, 最快将a和b值替换的方法为 a,b =b,a 今日内容 1. 字典 2. 集合 3.hash 4.基本数据类型总结 5.循环之for循环 6.range的使用 7.深 ...
 - 通过supper()有参构造器,完成子类对象调用父类属性的方法,并完成赋值
			
package com.Summer_0426.cn; /** * @author Summer * 通过supper()有参构造器,完成子类对象调用父类属性的方法,并完成赋值 * */ public ...
 - web服务器、tomcat、servlet是什么?它们之间的关系又是什么?
			
今天偶然看到常见web服务器的介绍有Apache HTTP server.Nginx.Microsoft IIS.GWS,心中不禁产生了疑问,这些都是什么呢?一直认为tomcat就是web服务器,以下 ...
 - 图像压缩编解码实验(DCT编码+量化+熵编码(哈夫曼编码))【MATLAB】
			
课程要求 Assignment IV Transform + Quantization + Entropy Coding Input: an intra-frame or a residue pict ...