演示jar包冲突的N种场景

126 阅读3分钟

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

image.png

1.2.24会最终生效。 因为子会继承父亲的属性,但是由于自己有这个属性,那么则覆盖! 继承一定会伴随着覆盖的,这个设计在编程语言中还是比较普遍的。

4.2 案例2

image.png 1.2.25会最终生效。 参考 单颗树在依赖在竞争时:当deep=1,即直接依赖。同级是靠后优先。 满足Maven的核心竞争依赖策略!

4.3 案例3

image.png

1.2.78最终会生效。 一个项目里的dependencyManagement只能对不声明version的dependency和间接依赖有效!

4.4 案例4

image.png 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

image.png

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. 常用命令

  1. mvn clean package -DSkipTest 直接进行打包,进行结果分析

  2. mvn dependency:tree 会把整个的maven的树形结构输出

  3. 批量改父工程version的命令 mvn versions:set -DnewVersion=0.0.3-SNAPSHOT