mvn dependency:tree
jar依赖冲突解决实践
前言
随着功能的增多,各种中间件的引入。应用以来的各种jar的规模极具膨胀,出现jar冲突和Class冲突的问题层出不穷,让人不胜其扰。本文针对冲突,提供一个排查和定位问题的最佳实践。实践中尽量不借助第三方工具,而使用maven或者Linux的自带命令行。
Maven构建的应用的jar冲突
目前最为最流行的项目构建和管理工具,在目前的互联网应用中被广泛使用。maven框架很大的一个便利就是对于jar的依赖管理,它自然提供了一些工具帮助开发者进行依赖分析。maven存在坐标的概念。groupId,artifactId,version三个维度定位到一个唯一的jar。
1 |
<dependency> |
对于版本,有一个很宽泛的范围
[3.6.0,4.0.0) 要求的依赖版本>=3.6.0且<4.0.0
[,3.6.0] 要求的依赖版本<=3.6.0
对于应用来讲,还是固定一个版本为好,夸版本有太多不可预知的情况存在。
静态代码检查
通过mvn dependency:tree 命令查看依赖树
1 |
[INFO] \- com.alibaba.china.shared:credit_shared.ruleengine.biz:jar:1.0-SNAPSHOT:compile |
通过静态代码扫描的方式,能分析出来jar之间的依赖关系。举例credit_shared.ruleengine.biz-1.0-SNAPSHOT.jar依赖了antlr-3.3.jar。org.antlr:antlr-3.3.jar在maven中的坐标是
1 |
<dependency> |
依赖仲裁
从上面的依赖树,出现了另外一个版本的jar——org.antlr:antlr:jar:2.7.7:compile,这就出现了依赖仲裁的问题。
maven 2.2.1版本仲裁规则:
- 按照项目总POM的DependencyManager版本声明进行仲裁(覆盖),但无警告
- 如无仲裁声明,则按照依赖最短路径确定版本
- 若相同路径,有严格区间限定的版本优先
- 若相同路径,无版本区间,则按照先入为主原则
如要解决冲突问题,很多时候都用到exclusions,如A->B->D(v1),A->C-D(v2),要指定A->D(v1),则需要在声明C的依赖时候通过exclusions列表排除掉对D(v2)的依赖。
要更好理解依赖仲裁,需要了解以下附带知识。
maven classpath
maven中有三种classpath:
- 编译classpath:编译项目代码,依赖的jar会被引入到classpath
- 测试classpath:编译和执行测试部分代码,如单元测试,集成测试,依赖会被引入到classpath
- 运行classpath:实际运行代码的时候,依赖的jar会被引入到classpath
scope:依赖范围
scope就是为了解决jar在classpath中的可见性。scope有以下几个可选项
compile:默认值,对编译classpath、测试classpath、运行classpath都有效,在三个阶段都需要指定的jar
provided:编译和测试可用,不会被传递依赖,不会被打包。例:依赖于web容器中的提供的一个jar包,在编译的时候需要加入依赖(web容器还没有介入),运行的时候由web容器来提供。如servlet-api。
test:执行单元测试时可用,不会被打包,不会被传递依赖
runtime:运行和测试时需要,但编译时不需要。最典型的例子是JDBC的驱动,编译时只需要提供驱动的API即可,在运行和测试阶段,需要加载到具体的驱动实现。
system:跟provided一致,显示制定依赖路径,一般是指定了本地的仓库之外的类库文件。可能造成不可依赖性,不推荐使用。
传递性依赖
A->B,B->C,则A->C。这是传递性依赖。依赖是有范围的,A->B,B->C的依赖范围决定了A->C的依赖范围。
A->C | compile | provided | test | runtime | |
---|---|---|---|---|---|
compile | compile | runtime | |||
provided | provided | provided | provided | ||
test | test | test | |||
runtime | runtime | runtime |
可选依赖
1 |
<dependency> |
A->B,B->C(可选),B->D(可选),则A不会通过传递依赖到C或者D。
非Maven项目或者不同坐标的jar出现Class冲突,
上面介绍的是jar相同而版本不同,如antlr-3.3.jar,antlr-3.2.jar类似情况的冲突解决方案。这种情况一般出现在中间件升级。下面介绍坐标不同,如antlr-old-3.3.jar、antlr-new.jar,而jar中包含了类路径完全相同的类的情况。
出现这种情况,一般的异常提示都是“XXX类has no such method XXXX”之类的。这些异常提示基本可以定位成Class不是你要的Class,只不过Class的全路径是相同的,最大的可能也就是ClassLoader加载了另外一个jar的同名类。所以,首先要排查到该类是从哪个具体jar中来的。JVM提供了这样的功能,查看加载类的情况
1 |
java -verbose:class |
类加载情况,如SubscriptionInfo类加载自file:/home/zhao/web-deploy/jettyserver/tmp/jetty-0.0.0.0-34200-root.war--any-/webinf/WEB-INF/lib/pc2.common-1.2.5.jar
1 |
[Loaded com.alibaba.pc2.common.remote.subscription.SubscriptionInfo from file:/home/zhao/web-deploy/jetty_server/tmp/jetty-0.0.0.0-34200-root.war-_-any-/webinf/WEB-INF/lib/pc2.common-1.2.5.jar] |
而同样在pmap pid可以进程的内存镜像。 jps -v查看pid,再通过pmap pid > map.txt,从map.txt中查到
1 |
00007fa4ae174000 20K r-xs- /home/zhao/web-deploy/jetty_server/tmp/jetty-0.0.0.0-34200-root.war-_-any-/webinf/WEB-INF/lib/pc2.common-1.2.5.jar |
得到确认后,如果是maven工程,则通过依赖树查询到是具体哪个jar依赖了这个错误引用,在pom文件中exclusions掉该jar即可。
如果是非maven工程,则通过其他方式把错误引用排除掉即可。
mvn dependency:tree的更多相关文章
- 查看maven项目的依赖关系 mvn dependency:tree
maven-dependency-plugin最大的用途是帮助分析项目依赖,dependency:list能够列出项目最终解析到的依赖列表,dependency:tree能进一步的描绘项目依赖树,de ...
- mvn dependency:tree的用法
一.参考文档 https://maven.apache.org/plugins/maven-dependency-plugin/examples/resolving-conflicts-using-t ...
- 7) mvn dependency:tree
http://maven.apache.org/plugins/maven-dependency-plugin/tree-mojo.html mvn dependency:tree 查看 <de ...
- Maven类包冲突终极三大解决技巧 mvn dependency:tree
Maven对于新手来说是<步步惊心>,因为它包罗万象,博大精深,因为当你初来乍到时,你就像一个进入森林的陌生访客一样迷茫. Maven对于老手来说是<真爱配方>,因为它无所不能 ...
- maven 查看依赖树结构命令mvn dependency:tree
使用maven 管理项目的依赖,可以使用如下命令查看依赖树结构: mvn dependency:tree 如下图是使用idea的终端执行命令的局部图: 也可以使用如下命令将输出定向到某个文件,这样就可 ...
- maven dependency:tree中反斜杠的含义
摘自:http://www.708luo.com/posts/2013/11/maven-dependency-slash-mark/ 一个mvn dependency:tree命令执行的输出如下: ...
- npm运行出错npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree
npm运行出错npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree 场景复现: 使用vue CLI创建项 ...
- websphere安装和mvn dependency:copy-dependencies
http://www.blogjava.net/paulwong/archive/2009/09/19/295657.html http://ljhzzyx.blog.163.com/blog/sta ...
- npm版本兼容导致的npm ERR! ERESOLVE unable to resolve dependency tree
当团队项目中,团队成员的npm包管理工具版本不一致时执行npm install报错: npm -v查看版本信息:7.x与6.x之间的兼容问题 解决方案: 一:升级或降级npm版本,保持一致npm in ...
随机推荐
- 【读书笔记】iOS-网络-HTTP-URL百分号编码
代码: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, ty ...
- centos安装lamp
http://bbs.qcloud.com/thread-1316-1-1.html 启动MySQL http://www.cnblogs.com/starof/p/4680083.html 修改密码 ...
- Linux下安装VSCode
进行下载 64位的包:地址: https://code.visualstudio.com/docs/?dv=linux64&build=insiders 1.解压: tar -zxvf cod ...
- SQLServer 学习笔记之超详细基础SQL语句 Part 6
Sqlserver 学习笔记 by:授客 QQ:1033553122 -----------------------接Part 5------------------- 28 聚合函数 --求平均分 ...
- SQLServer 2005客户端远程连接sql2008 数据库服务器
SQL2005客户端远程连接sql2008 数据库服务器 by:授客 QQ:1033553122 准备工作: 客户端所在pc机配置: 配置数据源 控制面板-管理工具-ODBC数据源-系统DSN-添加- ...
- 国内使用kubeadm部署kubernetes的完整流程
使用阿里云的镜像安装kubeadm和kubectl cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Ku ...
- pytest+allure+jenkins +python2.7
pip install lxml==3.8.0 pip install pytest-allure-adaptor
- python基础一数据类型之字典
摘要: python基础一数据类型之一字典,这篇主要讲字典. 1,定义字典 2,字典的基础知识 3,字典的方法 1,定义字典 1,定义1个空字典 dict1 = {} 2,定义字典 dict1 = d ...
- 红帽7中firewall常用指令
1.端口管理 (1)列出DMZ区域开放的端口 ~]#firewall-cmd --zone=dmz --list-ports (2)8080端口加入dmz区 ~]#firewall-cmd --zon ...
- ELF文件结构描述
ELF目标文件格式最前部ELF文件头(ELF Header),它包含了描述了整个文件的基本属性,比如ELF文件版本.目标机器型号.程序入口地址等.其中ELF文件与段有关的重要结构就是段表(Sectio ...