问题描述
在做maven项目的过程中,不知道大家会不会遇到这样的问题,明明代码方面没有什么问题,但是在运行的时候就会报出诸如 java.lang.ClassNotFoundException
、java.lang.NoSuchMethodError
、 java.lang.NoSuchFieldError
等问题。出现这种问题很大一部分可能是由于项目中产生了依赖冲突。举个简单的例子来说明下什么是依赖冲突
依赖冲突
假如在项目中引用d到了两个第三方提供的包 a.jar 和 b.jar , 其中a.jar 包中引用了一个 c.jar ,假设这个 c.jar 为0.1版本。此时项目引用的b.jar 中也引用了 c.jar ,但是这里的 c.jar 包的版本为0.2版本,比 a.jar 中的 c.jar 版本更高。b.jar 中某个类引用了 c.jar 的类 classA 中的方法 method A() ,并且该方法只存在于高版本的 c.jar(0.2版本) 的类 classA 中,而不存在c.jar(0.1版本) 的类 classA 中。
当系统编译加载时,由于maven对jar包的依赖次序不同,系统可能编译加载 c.jar(0.1版本) ,也可能编译加载 c.jar(0.2版本) ,当编译加载c.jar(0.2版本) 时,由于很多 jar 包都支持向下兼容,即高版本兼容低版本,因此不论 a.jar 调用 c.jar 还是 b.jar 调用 c.jar 一般都不会出问题。但如果此时刚好应用编译加载的是 c.jar(0.1版本) 中的类 classA 时,那么 b.jar 调用Method A() 时则会报 NoSuchMethodError 异常,因为 Method A() 函数只存在于高版本的 c.jar 中,而此时系统编译加载的却是低版本的 c.jar 。上面所描述的情况便是所谓的依赖冲突问题。
解决办法
解决思路
根据报错的class名或方法名定位到可能导致冲突的jar包(抛出异常后可以搜索下找不到的类或者方法存在于哪个包),然后定位这个jar包在项目中都存在哪些版本,排除掉低版本的jar包,只留下产生冲突jar包的最高版本即可解决。
方法一:maven依赖树
maven自带了jar的依赖树分析机制,在项目的根目录下执行 mvn dependency:tree -Dverbose > tree.txt
命令后,便可以生成一个tree.txt文件,这个文件里面输出的便是发生冲突jar文件。然后 exclusion 掉不想要的jar包即可。
方法二:使用Idea(推荐方法)
第一种方法一开始理解jar冲突的机制和熟悉maven命令的使用,但是解决起来不够便捷快速。当使用idea开发工具时,可以使用idea为我们提供的解决依赖冲突的利器。
在idea中打开项目的 pom.xml 文件,然后点击编辑器左下角的 Dependency Analyzer 选项卡,接下来选择其中的 Conflicts 选项,所列出来的便是项目中所有发生冲突的jar包,点击某个Jar包后会列出这个jar包都是由哪些jar包引入进来的,版本号等信息,然后对其中所有的低版本jar包点击右键选择 Exclude 便可解决冲突问题。
Ps:要是打开idea的pom文件后,左下角没有Dependency Analyzer选项卡,则下载安装 maven helper 和 maven intergration 这两个插件即可。
方法三:使用eclipse
eclipse中打开 pom.xml文件,切换到 hierarchy dependency 选项,右上角搜索对应发生冲突的包,便可清晰地看到冲突版本,排除不想要的版本即可。