Maven的核心概念
Maven核心概念概括
Maven的核心概念分为8个,分别是
-
约定的目录结构*
-
POM*
-
坐标*
-
依赖**
-
仓库
-
生命周期/插件/目标
-
继承
-
聚合
约定的目录结构*
约定的目录结构已经在创建Maven工程的时候说明,这里不做赘述,仅以下图表述约定的目录结构
POM*
含义:Project Object Model 项目对象模型
pom.xml对于Maven工程是核心的配置文件,与构建过程相关的一切设置都在这个文件中进行配置,重要程度相当于web.xml对于动态Web工程
坐标*
数学中的坐标
-
在平面上使用X、Y两个向量可以唯一的定位平面中的任何一个点
-
在空间中使用X、Y、Z三个向量可以唯一的定位空间中的任何一个点
Maven中的坐标
Maven中的坐标不像数学中的坐标一样去在平面或者空间中确定一个点,而是通过坐标去定位Maven仓库中每一个jar包的位置。
而Maven中的坐标也有三个向量,分别是
-
groupId:公司或组织域名倒序 + 项目名
-
artifactId:模块名
-
version:版本
在pom.xml中这样设置
<groupId>com.jinxin.maven</groupId> <artifactId>Hello</artifactId> <version>1.0.0</version>
Maven工程的坐标与仓库中路径的对应关系
groupId/artifactId/version/artifactId-version.jar
在Maven仓库中jar包的储存规则如上所示,例如上面的例子中的jar包的位置就是 com/jinxin/maven/Hello/1.0.0/Hello-1.0.0.jar
依赖**
依赖在Maven中非常非常非常重要!!!
pom.xml中依赖的写法

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
Maven解析依赖信息时会到本地仓库中查找被依赖的jar包
对于我们自己开发的Maven工程,使用mvn install命令安装后就可以进入仓库
常用的依赖范围(scope)
依赖范围 | 对主程序是否有效 | 对测试程序是否有效 | 是否参与打包 | Tips |
compile范围的依赖 | 有效 | 有效 | 参与 | |
test范围的依赖 | 无效 | 有效 | 不参与 | |
provided范围的依赖 | 有效 | 有效 | 不参与 |
开发时需要,部署时忽略,运行时由Servlet容器提供。例如servlet-api.jar |
依赖的传递性
什么是依赖的传递性?有的时候在导入某些工程的时候,那些工程还依赖于另外的工程,那么还需不需要在本工程中将这些被依赖所依赖的工程导入呢?答案是不用,因为依赖的传递性这一特性,在导入某个工程时,它所依赖的依赖也都导入了过来,因此不必要再去重复的导入
以spring-core为例
在上面的例子中,Hello工程导入了spring-core的依赖,而spring-core又依赖于commons-logging,但是此时不必在Hello中再导入commons-logging了,因为已经随着spring-core传递过来了
依赖传递性的好处:可以传递的依赖不必在每个模块中都重复声明,在”最下面”的工程中依赖一次即可
注意:非compile范围的依赖不能传递
依赖的排除
为什么需要排除依赖?有的时候对于一些依赖,不能删又不想导入,这个时候就要用到依赖的排除了。在使用了依赖的排除后,像之前导入spring-core依赖时commons-logging也会传递过来的情况就不存在了
排除方法:在对应的dependency标签中加入下面一段代码
<exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions>
依赖的原则
作用:解决模块工程之间jar包的冲突问题
对于test范围的jar包,会在多个工程中被反复依赖,那么当一个父工程同时调用了两个子工程,这两个子工程中都有同一个依赖,而父工程也刚好要使用这个依赖,那么问题出现了,该使用两个子工程中哪一个工程中的依赖好呢?Maven给出了两种解决方案
验证路径最短者优先
在上面的例子中,HelloFriend跟Hello中都有log4j依赖,那么MakeFriends该调用谁的log4j呢?从上面的图中我们不难观察出MakeFriends要找到Hello的log4j要经过3下,而要找到HelloFriend的log4j只需要两下。那么这个时候肯定会使用路径短的,这就是路径最短者优先
验证路径相同时先声明者优先,先声明指的是dependency标签的声明顺序
上面解决了路径不同时使用依赖的问题,那么如果路径相同时该怎么办呢?
就如上图,这下找两个log4j都只需要两步,那么还用路径最短优先原则肯定不行了,因而Maven又给出了另一个规则,就是在pom.xml文件中先导入的依赖优先,也就是谁的dependency标签写在前面就用谁的
统一管理依赖的版本
为什么要使用统一管理版本?例如下图对Spring各个jar包的依赖版本都是4.0.0。
如果需要将上面的依赖统一升级为4.1.1怎么办?手动逐一修改肯定是不可靠的,这时就需要使用另外一种方式配置版本信息了
-
首先使用properties标签内使用自定义标签统一声明版本号
-
然后在需要统一版本的位置使用${自定义标签名}来引用声明的版本号即可
<properties> <spring.version>4.0.0.RELEASE</spring-version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${ spring.version }</version> <scope>compile</scope> </dependency> </dependencies>
其实使用properties标签内使用自定义标签的方式不只是可以声明版本号,还可以用于其他的地方
仓库
仓库的分类
- 本地仓库:当前电脑上部署的仓库目录,为当前电脑上所有Maven工程服务
-
远程仓库
-
私服:搭建在局域网环境中,为局域网范围内所有Maven工程服务
-
中央仓库:架设在Internet上,为全世界所有的Maven工程服务
-
中央仓库镜像:为了分担中央仓库的流量,提升用户访问的速度
-
仓库中保存的内容
仓库中保存的是Maven工程
-
Maven自身所需要插件
-
第三方框架或工具的jar包(第一方是JDK,第二方是我们自己)
-
我们自己开发的Maven工程
生命周期/插件/目标
- 各个构建环节执行的顺序:不能打乱顺序,必须按照既定的正确顺序来执行
- Maven的核心程序中定义了抽象的生命周期,生命周期中各个阶段的具体任务是由插件来完成的
- Maven核心程序为了更好的实现自动化构建,按照这样的特点执行生命周期中的各个阶段:不论现在要执行生命周期中的哪一个阶段,都是从生命周期最初的位置开始执行
- 插件和目标
- 声明周期的各个阶段仅仅定义了要执行的任务是什么
- 各个阶段和插件的目标是对应的
- 相似的目标由特定的插件来完成
- 可以将目标看成”调用插件功能的命令”
继承
现状:由于test范围的依赖不能传递,所以必然会分散在各个模块工程中,很容易造成版本不一致
需求(以junit为例):统一管理各个模块工程中对junit依赖的版本
解决思路:将junit依赖统一提取到”父”工程中,在子工程中声明依赖时不指定版本,以父工程中统一设定的为准
操作步骤
创建一个Maven工程作为父工程。注意:打包的方式pom
<groupId>com.jinxin.maven</groupId> <artifactId>Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging>
在子工程中声明对父工程的引用
<!-- 子工程中声明父工程 --> <parent> <groupId>com.jinxin.maven</groupId> <artifactId>Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 以当前文件为基准的父工程pom.xml文件的相对路径 --> <relativePath>../Parent/pom.xml</relativePath> </parent>
将子工程的坐标与父工程坐标中重复的内容删除
在父工程中统一junit的依赖
<!-- 配置依赖的管理 --> <dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.0</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement>
经过如上配置即可
聚合
作用:一键安装各个模块工程
有的时候再安装自己的Maven工程时由于自己的工程中引入了其他的自己的Maven工程,这时在仓库中到不到该工程,去中央仓库也没有的情况下就会报错,这时使用聚合就可以连带着把这个项目也安装
配置方式:在一个总的聚合工程中配置各个参与聚合的模块
<!-- 配置聚合 --> <modules> <!-- 指定各个子工程的相对路径 --> <module>../Hello</module> <module>../HelloFriend</module> <module>../MakeFriends</module> </modules>
使用方式:在聚合的工程处安装 mvn install