Maven中jar包冲突原理与解决办法
Maven中jar包冲突是开发过程中比较常见而又令人头疼的问题,我们需要知道 jar包冲突的原理,才能更好的去解决jar包冲突的问题。本文将从jar包冲突的原理和解决两个方面阐述Maven中jar包冲突的解决办法。
一、Maven中jar包冲突产生原因
MAVEN项目运行中如果报如下错误:
Caused by:java.lang.NoSuchMethodError
Caused by: java.lang.ClassNotFoundException
十有八九是Maven jar包冲突造成的。那么jar包冲突是如何产生的?
首先我们需要了解jar包依赖的传递性。
1、依赖传递
当我们需要A的依赖的时候,就会在pom.xml中引入A的jar包;而引入的A的jar包中可能又依赖B的jar包,这样Maven在解析pom.xml的时候,会依次将A、B 的jar包全部都引入进来。
举个例子:
在Spring Boot应用中导入Hystrix和原生Guava的jar包:
<!--原生Guava API--> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>20.0</version> </dependency> <!--hystrix依赖(包含对Guava的依赖)--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>1.4.4.RELEASE</version> </dependency>
利用Maven Helper插件得到项目导入的jar包依赖树:
从图中可以看出Hystrix包含对Guava jar包依赖的引用: Hystrix -> Guava,所以在引入Hystrix的依赖的时候,会将Guava的依赖也引入进来。
2、jar包冲突原理
那么jar包是如何产生冲突的?
假设有如下依赖关系:
A->B->C->D1(log 15.0):A中包含对B的依赖,B中包含对C的依赖,C中包含对D1的依赖,假设是D1是日志jar包,version为15.0
E->F->D2(log 16.0):E中包含对F的依赖,F包含对D2的依赖,假设是D2是同一个日志jar包,version为16.0
当pom.xml文件中引入A、E两个依赖后,根据Maven传递依赖的原则,D1、D2都会被引入,而D1、D2是同一个依赖D的不同版本。
当我们在调用D2中的method1()方法,而D1中是15.0版本(method1可能是D升级后增加的方法),可能没有这个方法,这样JVM在加载A中D1依赖的时候,找不到method1方法,就会报NoSuchMethodError
的错误,此时就产生了jar包冲突。
注:
如果在调用method2()方法的时候,D1、D2都含有这个方法(且升级的版本D2没有改动这个方法,这样即使D有多个版本,也不会产生版本冲突的问题。)
举个例子:
利用Maven Helper插件分析得出:Guava这个依赖包产生冲突。
我们之前导入了Guava的原生jar包,版本号是20.0;而现在提示Guava产生冲突,且冲突发生位置是Hystrix所在的jar包,所以可以猜测Hystrix中包含了对Guava不同版本的jar包的引用。
为了验证我们的猜想,使用Maven Helper插件打印出Hystrix依赖的jar tree:
可以看到:Hystrix jar中所依赖的Guava jar包是15.0版本的,而我们之前在pom.xml中引入的原生Guava jar包是20.0版本的,这样Guava就有15.0 与20.0这两个版本,因此发生了jar包冲突。
二、 Maven中jar包冲突的解决方案
Maven 解析 pom.xml 文件时,同一个 jar 包只会保留一个,那么面对多个版本的jar包,需要怎么解决呢?
1、 Maven默认处理策略最短路径优先
Maven 面对 D1 和 D2 时,会默认选择最短路径的那个 jar 包,即 D2。E->F->D2 比 A->B->C->D1 路径短 1。
最先声明优先
如果路径一样的话,如: A->B->C1, E->F->C2 ,两个依赖路径长度都是 2,那么就选择最先声明。
2、移除依赖:用于排除某项依赖的依赖jar包
(1)我们可以借助Maven Helper插件中的Dependency Analyzer分析冲突的jar包,然后在对应标红版本的jar包上面点击execlude,就可以将该jar包排除出去。
再刷新以后冲突就会消失。
(2)手动排除
或者手动在pom.xml中使用<exclusion>
标签去排除冲突的jar包(上面利用插件Maven Helper中的execlude方法其实等同于该方法):
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>1.4.4.RELEASE</version> <exclusions> <exclusion> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </exclusion> </exclusions> </dependency>
mvn分析包冲突命令:
mvn dependency:tree
3 版本锁定原则:一般用在继承项目的父项目中
正常项目都是多模块的项目,如moduleA和moduleB共同依赖X这个依赖的话,那么可以将X抽取出来,同时设置其版本号,这样X依赖在升级的时候,不需要分别对moduleA和moduleB模块中的依赖X进行升级,避免太多地方(moduleC、moduleD…)引用X依赖的时候忘记升级造成jar包冲突,这也是实际项目开发中比较常见的方法。
首先定义一个父pom.xml,将公共依赖放在该pom.xml中进行声明:
<properties> <spring.version>spring4.2.4</spring.version> <properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.versio}</version> </dependency> </dependencies> </dependencyManagement>
这样如moduleA和moduleB在引用Spring-beans jar包的时候,直接使用父pom.xml中定义的公共依赖就可以:
moduleA在其pom.xml使用spring-bean的jar包(不用再定义版本):
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </dependency> </dependencies>
moduleB在其pom.xml使用spring-bean的jar包如上类似:
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </dependency> </dependencies>
以上就是日常开发中解决Maven冲突的几个小方案,当然实际开发中jar包冲突的问题可能远远比这个更复杂,需要具体问题具体处理。更多相关Maven jar包冲突内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
解决执行maven命令时提示Process terminated的问题
这篇文章主要介绍了解决执行maven命令时提示Process terminated的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25- 这篇文章主要介绍了解决idea2020 maven无法自动导包的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-13
解决IDEA maven 项目修改代码不生效,mvn clean、install后才生效
这篇文章主要介绍了解决IDEA maven 项目修改代码不生效,mvn clean、install后才生效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25- 这篇文章主要介绍了idea 打包maven项目忽略test文件的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
详解Maven profile配置管理及激活profile的几种方式
这篇文章主要介绍了详解Maven profile配置管理及激活profile的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-26- 这篇文章主要以实例的方式讲解了避免javascript冲突的方法,具有一定的参考价值,感兴趣的朋友可以参考一下...2016-01-07
- 这篇文章主要介绍了详解idea从git上拉取maven项目详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-08-12
使用Maven 搭建 Spring MVC 本地部署Tomcat的详细教程
这篇文章主要介绍了使用Maven 搭建 Spring MVC 本地部署Tomcat,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-08-16- 这篇文章主要介绍了Maven打包的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-13
- 这篇文章主要介绍了idea+maven打jar包的两种方式,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-07-16
idea2020.3配置maven环境并配置Tomcat的详细教程
这篇文章主要介绍了idea2020.3配置maven环境并配置Tomcat的详细教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-19- 这篇文章主要介绍了使用maven的profile构建不同环境配置的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-26
- 这篇文章主要介绍了完美处理Python与anaconda环境变量的冲突问题,对anaconda感兴趣的同学,可以参考下...2021-04-07
maven 在执行package,install,deploy时使用clean与不使用clean的不同之处
有时候用mvn install后,新改的内容不生效,一定要后来使用mvn clean install 才生效,由于之前没有做记录,以及记不清是什么情况下才会出现的问题,于是想看看clean和不clean的区别,感兴趣的朋友跟随小编一起看看吧...2021-08-03gateway与spring-boot-starter-web冲突问题的解决
这篇文章主要介绍了gateway与spring-boot-starter-web冲突问题的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-17- 这篇文章主要介绍了使用idea远程调试jar包的配置过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-26
使用maven开发springboot项目时pom.xml常用配置(推荐)
这篇文章主要介绍了使用maven开发springboot项目时的pom.xml常用配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-08- 这篇文章主要介绍了idea克隆maven项目的方法步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-05
- 这篇文章主要介绍了如何将tomcat源码以maven方式运行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
快速解决jquery.touchSwipe左右滑动和垂直滚动条冲突
这篇文章主要介绍了快速解决jquery.touchSwipe左右滑动和垂直滚动条冲突问题,感兴趣的小伙伴们可以参考一下...2016-04-18