maven依赖树
00 依赖树结构
通常在pom.xml中声明依赖后,maven引入直接依赖,并通过直接依赖的pom.xml讲传递性依赖导入到当前项目,这样层层递进最终构成了一个树状的依赖关系

深度优先遍历,并通过缓存节点剪枝。a-b-e路径会缓存e子树,a-c-e发现e已经被缓存会立刻返回。
01 依赖调解

针对如图这种情况,a依赖d的哪个版本呢?
maven采用短路径优先的原则,a-b-d这个路径的d会被使用,即a会依赖d的1.0版本。
02 循环依赖

mvn dependency:tree -Dverbose |grep cycle 可以用来查看是否存在循环依赖
如果存在循环依赖,很多人通过exclusion来解决依赖冲突
03 依赖排除

Exclusion会降低maven依赖解析的效率
如上图中的,我们在c处对log4j进行了exclusion,那么abe解析的时候,会缓存e子树,当ace解析到e的时候,由于要exclusion,所以e子树不能直接被使用,需要重新带上exclusion条件重新解析e。
结论如下:
- exclusion会造成依赖重复扫描和缓存(因为增加了exclusion,原有的相关子树缓存,需要重新扫描)
- 在子树的越靠近叶子节点的地方作exclusion,影响范围越小。
- 依赖树高度越高,引入exclusion的代价就越大。
当前公司由于依赖关系复杂,依赖树层次过高,且各个依赖的扇出范围都过于庞大,没引入一个exclusion都会带来指数级的副作用,IDEA的reimport时间过长,失败,本地打包出现oom等都是这个问题的部分表现,重复缓存导致maven进程内存堆利用率过高,一致出发FullGC。
如何应对:要求sdk的提供方暴露轻量级sdk,避免引入类似kuai'shou-component这样的巨型依赖,保证依赖树的高度在适当范围内。
现有临时解决办法只能适当调大IDEA和maven的Xmx,去掉复杂的exclusion申明。
04 依赖可视化
mvn dependency:tree -Dverbose可以得到文本输出的依赖树关系
mvn dependency:tree -DoutputType=dot 得到dot定义的输出,通过Graphviz(brew install graphviz安装)将digraph渲染成图片
IDEA里的pom.xml右键Diagrams->Show dependencies也可以,但是依赖关系复杂时效果较差