1. 背景
印象最深的就是以前在某中厂做服务上云,解决项目中的log4J jar冲突,今天公司某位同事分享了一下,就此做个总结
参考文章: mp.weixin.qq.com/s/flniMiP-e…
2. 介绍
2.1 影响依赖的标签都有哪些
1.<dependencies>
2.<dependencyManagement>
只声明但不发生实际引入,作为依赖管理。依赖管理是指真正发生依赖的时候,再去参考依赖管理的数据。
这样使用dependency的时候,可以缺省version。
另外<dependencyManagement> 还可以管控所有的间接依赖,即使间接依赖声明了version,也
要被覆盖掉。
3.<parent>
4.<properties>
2.2 依赖的作用域都有哪些
compile和runtime会参与最后的打包环节,其余的都不会。compile可以不写。
test只会对 src/test目录下的测试代码起作用。
provided是指线上已经提供了这个Jar包,打包的时候不需要在考虑他了,一般像servlet的包很多都是provided。
system和provided没什么太大的区别。
2.3 jar结构
<groupId> : com.alibaba 一般是公司的名称
<artifactId> : fastjson 项目名称
<version> : 1.2.24 版本号
3. jar包冲突分析
当deep=1,即直接依赖。同级是靠后优先。
当deep>1,即间接依赖。同级是靠前优先。
maven里最重要的2个关系,分别是继承关系和依赖关系。我们所有的规律都应该只从这2个关系入手
4. 案例分析
4.1 案例1
1.2.24会最终生效。 因为子会继承父亲的属性,但是由于自己有这个属性,那么则覆盖! 继承一定会伴随着覆盖的,这个设计在编程语言中还是比较普遍的。
4.2 案例2
1.2.25会最终生效。
参考 单颗树在依赖在竞争时:当deep=1,即直接依赖。同级是靠后优先。
满足Maven的核心竞争依赖策略!
4.3 案例3
1.2.78最终会生效。 一个项目里的dependencyManagement只能对不声明version的dependency和间接依赖有效!
4.4 案例4
1.2.25会最终生效。这个比较复杂。
〇: 首先根据父子的继承关系,1.2.24会覆盖掉1.2.78。所以78版本淘汰
一: 由于一个项目里的dependencyManagement只能对不声明version的dependency和间接依赖有效,所以
1.2.77无法对1.2.25起作用。
二: 由于父子的继承关系,1.2.25会覆盖掉1.2.24.
所以最终1.2.25胜出!
4.5 案例5
1.2.77会最终生效。首先根据父子的继承关系,1.2.24会覆盖掉1.2.78。所以78版本淘汰,由于一个项目里的dependencyManagement是可以对不声明的version起作用,所以子pom的版本为1.2.77,由于父子的继承关系,1.2.77会覆盖掉1.2.24.,所以最终1.2.77胜出!
5. 结论
1.子pom声明版本在安全视角是非常危险的,子pom不应该显示声明版本。
2.主POM的dependencyManagent可以管控到 间接依赖 和 不显示声明version的直接依赖。
3.主POM的dependencies不能出现危险版本。否则子pom天然的继承了这个危险版本参与打包。
6. 常用命令
-
mvn clean package -DSkipTest 直接进行打包,进行结果分析
-
mvn dependency:tree 会把整个的maven的树形结构输出
-
批量改父工程version的命令 mvn versions:set -DnewVersion=0.0.3-SNAPSHOT