【maven】 依赖树(dependency、dependencyManagem
相关文章:
maven pom.xml详解
maven 依赖树(、)
使用 -boot- 方便管理项目依赖 1. 概述
boot工程示例:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0modelVersion><parent><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-parentartifactId><version>2.5.4version><relativePath/> parent><groupId>com.examplegroupId><artifactId>demoartifactId><version>0.0.1-SNAPSHOTversion><name>demoname><description>Demo project for Spring Bootdescription><properties><java.version>11java.version>properties><modules><module>mall-commonmodule><module>mall-ordermodule>modules><properties><java.version>1.8java.version><spring-cloud.version>Hoxton.SR8spring-cloud.version>properties><dependencies><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-webartifactId>dependency><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-testartifactId><scope>testscope>dependency>dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloudgroupId><artifactId>spring-cloud-commonsartifactId><version>${spring-cloud.version}version>dependency>dependencies>dependencyManagement><build><plugins><plugin><groupId>org.springframework.bootgroupId><artifactId>spring-boot-maven-pluginartifactId>plugin>plugins>build>project>
1.1 父pom中的
下引用的maven 依赖,默认被其子模块全部依赖,其子模块不用显示引用
优点:所有的子模块,不用再次引用,公用父模块的引用和版本号管理
缺点:子模块引用冗余,对于自己不需要引用的包,也会被引用过来
1.2 父pom中的
父pom通过管理,引用相关maven依赖后,子模块需要再次引用,但是不需要设置版本号。版本号由父pom中的 引用的依赖及版本号统一管理
若子模块中,想单独升级某一个依赖的版本号,则可在子模块中针对某个依赖添加版本号,此时子模块下的那个依赖的版本号会覆盖父pom对该依赖设置的版本号
优点:父pom 统一管理各个依赖的版本号,子模块可以按需要引用自己需要的依赖,灵活设置自己需要的依赖版本号或直接依赖父pom的版本号
缺点:子模块pom中要显示引用自己需要的依赖
2. 查看依赖树
CMD命令行下,进入pom.xml所在的目录,可以是父模块的目录,也可以是子模块的目录,区别在于前者会按子模块分级,展示所有模块的依赖树,后者只查子模块自身相关的依赖树,后者的结果是前者的一个子集。
mvn dependency:tree
mvn dependency:tree >d:/tree.txt
表示按条件过滤,表示显示详细信息,方便处理冲突
mvn :tree - -=[:][:]
括号中的参数是可选项
mvn dependency:tree -Dverbose -Dincludes=org.springframework:spring-tx
3. 处理冲突 3.1 处理冲突的原则
简介:处理jar包依赖冲突,首先,对于多个jar包都引用同一jar包的情况,最好是在程序中显式定义被共同引用的jar包的依赖,来统一版本号,方便维护
如果A和B都依赖同一jar包C,可能会出现两种情况
1.A和B引用的C版本相同
这时按照pom定义顺序选择第一个即可,没有冲突问题,如果在项目的maven中显示定义了C依赖,那么用选择项目定义的依赖,反正都一样,没有影响
2.A和B依赖的C版本不同
选择版本高的那个,这时会出现两种结果
(1) 高版本兼容低版本,所以不会出现问题
(2)高版本不兼容低版本,假如A依赖C2版本,B依赖C3版本,C3不兼容C2,maven选择了高版本C3,对A来说会出现问题
有3种解决方法
[1]提升A版本,找到依赖C3的A版本
[2]如果B版本也可依赖C2,在项目的maven中显示定义对C2的依赖,这样所有都使用C2版本
[3]如果B版本不支持C2版本,只能降低B版本,找到依赖C2的B版本
从功能性和可维护性考虑,高版本提供的功能更多,bug更少,优先考虑1,再考虑2,最后考虑3
3.2 如何处理冲突 3.2.1、maven自动解决依赖冲突的规则是什么?
第一原则:路径最近者优先
项目A有如下的依赖关系:
A->B->C->X(1.0)
A->D->X(2.0)
则该例子中,X的版本是2.0
####第二原则:路径相等,先声明者优先
项目A有如下的依赖关系:
A->B->Y(1.0)
A->C->Y(2.0)
若pom文件中B的依赖坐标先于C进行声明,则最终Y的版本为1.0
3.2.2 如何从依赖树中找到自己预期的版本,是被哪个jar给覆盖了?
先来看个最简单的例子
例1:仅涉及单个工程或模块
slf4j-仅依赖slf4j-api这一唯一的包,前者我们定义1.7.22,但是我们故意把后者单独引入一个1.7.25的高版本
<!--slf4j-log4j12 ,slf4j-api 均是直接引入--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.22</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.25</version></dependency>
下面是依赖树日志:
[INFO] +- org.slf4j:slf4j-log4j12:jar:1.7.22:compile
[INFO] | +- (org.slf4j:slf4j-api:jar:1.7.22:compile - omitted for conflict with 1.7.25)
[INFO] | \- log4j:log4j:jar:1.2.17:compile
[INFO] \- org.slf4j:slf4j-api:jar:1.7.25:compile
for 一般是指存在2个版本有冲突,至少出现一次直接引用(个人总结的,也不一定对,比如如果没有一个直接引入的,但是有2个间接引入的,会有该关键词出现吗?)。这个例子slf4j-和slf4j-api都是直接引入的。
插件也能方便的帮助我们查看依赖树,切换pom.xml至 标签页
扩展知识,怎么知道slf4j-会有个默认依赖的slf4j-api?
原因是每个jar自身也是有pom.xml的,我们查看本地仓库的slf4j-
例如 D:\maven\repo\org\slf4j\slf4j-\1.7.22\slf4j--1.7.22.pom,里面有如下配置:
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><type>test-jar</type><version>${project.version}</version><scope>test</scope></dependency>
现在一目了然,一层层的依赖就是这么来的。
例2:涉及父子模块
在查看依赖树之前我们先来了解一下的用法。
在包含父子项目中,允许在顶层的POM文件中,定义元素。通过它元素来管理jar包的版本,让子项目中引用一个依赖而不用显示的列出版本号。Maven会沿着父子层次向上走,直到找到一个拥有元素的项目,然后它就会使用在这个元素中指定的版本号。
在父模块中定义了org.slf4j为高版本1.7.25,子模块中定义了slf4j-为低版本1.7.22
/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>my</groupId><artifactId>myParent</artifactId><version>0.0.1-SNAPSHOT</version><!--父模块类型为pom --><packaging>pom</packaging><modules><!--定义子模块 --><module>mychild</module></modules><dependencyManagement><!-- 这样做的好处:统一管理项目的版本号,确保应用的各个项目的依赖和版本一致 --><dependencies><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.25</version></dependency></dependencies></dependencyManagement>
/pom.xml
<parent><groupId>my</groupId><artifactId>myParent</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>mychild</groupId><artifactId>mychild</artifactId><dependencies>
<!--直接引入slf4j-log4j12,但是间接引入slf4j-api--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.22</version></dependency></dependencies>
依赖树
\- org.slf4j:slf4j-log4j12:jar:1.7.22:compile+- org.slf4j:slf4j-api:jar:1.7.25:compile (version managed from 1.7.22)\- log4j:log4j:jar:1.2.17:compile
与例1相比,这里只有slf4j-作直接引入,slf4j-api是间接引入。
里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且和scope都读取自父pom。
例3
本例基于例2,注意把slf4j-api也改为直接引入
/pom.xml
<dependencies><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.22</version></dependency><!--与例2 相比,新增了直接引入slf4j-api--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.22</version></dependency></dependencies>
[INFO] +- org.slf4j:slf4j-log4j12:jar:1.7.22:compile
[INFO] | +- (org.slf4j:slf4j-api:jar:1.7.25:compile - version managed from 1.7.22; omitted for conflict with 1.7.22)
[INFO] | \- log4j:log4j:jar:1.2.17:compile
[INFO] \- org.slf4j:slf4j-api:jar:1.7.22:compile
例4
本例基于例2,额外间接引用slf4j-api,总共有2次额外引用
/pom.xml
<!-- 间接引用slf4j-api --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.22</version></dependency><!-- 新增间接引用slf4j-api --><dependency><artifactId>kafka-clients</artifactId><groupId>org.apache.kafka</groupId><version>2.1.1</version></dependency>
依赖树:
+- org.slf4j:slf4j-log4j12:jar:1.7.22:compile| +- org.slf4j:slf4j-api:jar:1.7.25:compile (version managed from 1.7.22)| \- log4j:log4j:jar:1.2.17:compile\- org.apache.kafka:kafka-clients:jar:2.1.1:compile+- com.github.luben:zstd-jni:jar:1.3.7-1:compile+- org.lz4:lz4-java:jar:1.5.0:compile+- org.xerial.snappy:snappy-java:jar:1.1.7.2:compile\- (org.slf4j:slf4j-api:jar:1.7.25:compile - version managed from 1.7.22; omitted for duplicate)
参考文章《maven冲突》