目录
一 maven基本常识
1.1 仓库
https://zhuanlan.zhihu.com/p/625000667
1.2 构建的生命周期
1. 清理程序
mvn clean命令是清除项目的编译内容,具体的效果是删除target目录
2. 编译程序
compile命令是对工程进行编译,具体效果是产生target目录,而编译又分为: 编译主程序和编译测试程序
2.1 编译主程序
mvn compile 命令是编译主程序,主程序编译之后的文件会生成在 target/classes 目录中
2.2 编译测试程序
mvn test-compile 命令是编译测试程序,测试程序编译之后的文件会生成在 target/test-classes 目录中
3. 执行测试
mvn test会执行测试程序中的所有测试用例,并且将生成的测试报告存放在target/surefire-reports目录下。
在执行mvn test命令的过程中,会自动先执行mvn clean、mvn compile、mvn test-compile,然后再执行mvn test进行测试
4. 程序打包
mvn package命令会对程序进行打包,如果是javase工程会打成jar包,而javaweb工程则会打成war包,打包得到的结果会生成在target目录中
在执行mvn package命令的过程中,会自动先执行mvn clean、mvn compile、mvn test-compile、mvn test,然后再执行mvn package进行打包
5.安装包
mvn install 命令会将程序打成的包安装到本地仓库(针对jar包,war包安装到本地仓库意义不大)
在执行mvn install命令的过程中,会自动先执行mvn clean、mvn compile、mvn test-compile、mvn test、mvn package,然后再执行mvn package进行打包
安装的效果是将本地构建过程中生成的jar包存入Maven本地仓库。这个jar包在Maven仓库中的路径是根据它的坐标生成的。
1.3 依赖范围
compile:通常使用的第三方框架的 jar 包这样在项目实际运行时真正要用到的 jar 包都是以 compile 范围进行依赖的。依赖范围默认值是compile
二 maven的传递
2.1 依赖的作用
在 A 依赖 B,B 依赖 C 的前提下,C 是否能够传递到 A,取决于 B 依赖 C 时使用的依赖范围。
- B 依赖 C 时使用 compile 范围:可以传递
- B 依赖 C 时使用 test 或 provided 范围:不能传递,所以需要这样的 jar 包时,就必须在需要的地方明确配置依赖才可以。
2.2 案例1 依赖排除
2.3 案例排除例子
注意:排除中不需要写版本。
2.4 依赖传递冲突
2.4.1 路径优先
当出现相同资源的jar包时,版本有区别时,层级越浅,优先级越高,层级越深,优先级越低。如图,最终A选取的版本为:junit-3.8
2.4.2 声明优先
当资源层级相同时,配置顺序考前的覆盖顺序靠后的。选用的版本为junti-3.19。(层级相同,先配置者优先)
1.beijing模块:使用junit版本为:3.8.1
2.shenzhen模块,使用junit版本为:4.12
3.在工程【my-define-starter】中调用
a)先beijing模块,后shenzhen模块: 层级相同,先配置者优先,选择beijing工程的3.81.
b)先shenzhen模块,后beijing模块: 层级相同,先配置者优先,选择shenzhen模块的4.12
c)存在两个相同包的不同版本,一般情况下,maven的规范能帮我们选择一个版本,这里冲突后,安装maven机制,选择junit版本为3.8.1
能够成功打出包来
2.4.3 特殊优先
特殊优先:当同级配置(同一个配置文件)了相同资源的不同版本,后配置的覆盖先配置的。
如下图
2.4.4 依赖与声明管控
1.在A工程中,没有父继承,A工程中dependency依赖,且在dependencymanagement中声明锁定版本依赖,则本工程以dependency依赖使用版本为准,dependencymanagement中只是声明锁定,如图
2.4.5 继承与传递
A,B是继承关系,A是父工程(pom打包方式),B是子工程(通过parent标签继承),则A中的denpency版本信息不会传递。B工程需要指定具体依赖的同时,指定具体版本。或者在A工程通过dependencymanagement声明说定版本,B工程进行依赖指定的坐标,也是ok的。
2.4.5.1 场景1
场景1:在A工程依赖junit的版本为3.8,B工程继承A工程,B工程依赖junit不写version,会报错。
1.A工程依赖的junit版本3.8
2.B工程继承A工程,依赖junit坐标,不写版本信息,则A工程依赖的junit版本不会传递到B工程。因为是继承关系,没有在A工程进行声明版本。
3.在A工程使用《dependencymanagment》标签声明依赖锁定版本,如这里: junit使用版本4.12
4.B工程显示,junit版本为底座管控的版本4.12
2.4.5.2 场景2
1.父工程 使用dependency指定版本 4.8.2;父工程dependencymanagement锁定版本4.13
2.子工程继承,父工程声明的版本4.13
父工程锁定版本:4.13
2.4.6 声明管控标签与依赖标签区别
当<dependencymanagement>与<dependency>标注相同依赖坐标时,如果<dependency>声明了版本,则使用<dependency>标注的版本,如果<dependency>未声明版本时,则使用<dependencymanagement>管理的版本。
其实<dependencymanagement>管控的版本,在本层级工程以及子工程生效。
场景1:如果<dependency>声明了版本,则使用<dependency>标注的版本。
场景2:当dependency没有定义版本,则使用dependencymanagement管控的版本;
三 maven的继承
3.1 继承的作用与概念
1.maven的继承是指在maven的项目中,让一个项目从另一个项目中继承配置信息的机制。继承可以让我们在多个项目中共享同一配置信息,简化项目的管理和维护工作。
本质: 本质上是A工程的pom.xml中的配置继承了B工程中pom.xml的配置。
操作:在子工程的pom.xml文件中通过<parent>标签指定当前子工程的父工程
3.结构如下
3.2 继承的作用
在父工程中统一管理项目中依赖信息,进行统一的版本管理。在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本,各个子工程使用依赖的时候版本就统一了
它背后的需求是:
在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理。使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。
通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力
3.3 实操案例
3.3.1 父工程
1.父工程:打包方式为pom,只有打包方式为 pom 的 Maven 工程能够管理其他 Maven 工程。打包方式为 pom 的 Maven 工程中不写业务代码,它是专门管理其他 Maven 工程的工程。
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>
2.通过聚合定义,管理的子模块
3.在父工程中声明自定义属性
在需要的地方使用${}的形式来引用自定义的属性名:
4.在父工程中配置依赖的统一管理
父工程统一管理依赖信息,其中使用dependencyManagement标签配置对依赖的管理,被管理的依赖并没有真正引入到每个子工程,在子工程中还要指定依赖。
3.3.2 子工程
1.使用parent标签指定当前工程的父工程
2.定义子工程的坐标
如果子工程坐标中的groupId和version与父工程一致,那么可以省略
3.子工程依赖父工程定义好的依赖
1.子工程引用父工程中的依赖信息时,可以把版本号去掉。
2.把版本号去掉就表示子工程中这个依赖的版本由父工程决定。
3.具体来说是由父工程的dependencyManagement来决定。
4.子工程没写版本号,依赖的版本为父工程中管理的依赖版本;子工程写了版本号,与父工程不一致,子工程的版本会覆盖父工程的版本
四 maven的聚合
4.1 聚合的概念
maven聚合层是指将多个项目组织到一个父级项目中,通过触发父工程的构建统一按顺序触发子工程的构建过程。
4.2 聚合的作用
1.统一管理子项目的构建:通过聚合,可以将多个子项目组织在一起,方便管理和维护。
2.优化构建顺序:通过聚合,可以对多个项目进行顺序控制,避免出现构建依赖混乱导致构建失败的情况。
3.以 mvn install 命令为例:Maven 要求有父工程时先安装父工程;有依赖的工程时,先安装被依赖的工程。我们自己考虑这些规则会很麻烦。但是工程聚合之后,在总工程执行 mvn install 可以一键完成安装,而且会自动按照正确的顺序执行。
4.3 案例
1.在父工程中pro03-maven-module中定义3个子模块,其中04模块依赖模块05,模块05依赖于模块06。
经过mvn 的compile,package,install等命令:通过父工程的触发maven命令,引发所有子模块进行构建,产生反应堆。,可以看到执行顺序为
Maven 要求有父工程时先安装父工程;有依赖的工程时,先安装被依赖的工程。06先执行,然后05,然后04。(其中04模块依赖模块05,模块05依赖于模块06。)
4.4 循环依赖问题
如果A工程依赖B工程,B工程依赖C工程,C工程又反过来依赖A工程,那么在执行构建操作时会报下面的错误:
[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:
这个错误的含义是:循环引用。
五 jar包冲突
5.1 使用maven helper插件
maven helper插件,它能够给我们罗列出来同一个jar包的不同版本,以及他们的来源,但是对不同jar包中同名的类没有办法。
5.2 安装使用
在settings=》plugins
5.3 解决案例
1.依赖
2.冲突查看 : maven锁定的spring-aop的版本5.3.23
2.进行排除
3. 查看pom文件
4.查看,5.2.3 aop没有冲突了!!!!
六 资源无法下载
6.1 maven中资源无法下载
在使用maven构建项目时,可能会发生依赖项下载错误的情况,主要原因是:
1.下载依赖时出现网络故障或仓库服务宕机等原因,导致无法连接至maven仓库,从而无法下载依赖。
2.依赖项的版本号或配置文件中的版本错误,或者依赖项没有正确的定义,导致maven下载的 依赖项羽实际需要的不一致,从而引发错误。
3.本地maven仓库或者缓存污染或损坏,导致maven无法正确的的使用现有的依赖项,并且也无法更新下载。
4.当我们要求Maven重新下载时,Maven看到这个jar包的扩展名是lastUpdated,jar包的扩展名是xxx.jar.lastUpdated,Maven就不会重新下载了。
解决方案:https://zhuanlan.zhihu.com/p/625000667
1.检查网络连接和maven仓库服务器状态
2.确保依赖项的版本号和项目对应的版本号匹配,并检查pom文件中的依赖项是否正确。
3.清除本地maven仓库缓存(lastupdate),因为只要存在lastupdated缓存文件,刷新也不会重新下载,本地仓库中,根据依赖的gav属性,依次向下查找文件夹,最终删除内部的文件,则重新下载即可。