因:
了解出现Maven依赖冲突的原因首先了解一下Maven的仲裁机制:
- 优先按照依赖中<dependencyManagement>元素中指定的版本进行仲裁(此时下面2个无效)
- 无版本声明,则按照“最短路径”原则进行仲裁,选择依赖树中路径最短的版本
- 如果路径长度一致,则按照“第一声明”原则进行仲裁,即pom中最先声明的版本
原因总结:
-
传递依赖导致不同的jar包冲突——maven会采用‘最短路径’选择jar。如果排除的是旧版本的jar包,直接调用最新jar有的方法,就会报ClassnotFound错误。
最短路径
如图,我们显示依赖了 spring-boot1.5.9,和spring-core4.0.8(当然这种情况在正常情况下不会发生)
在这种情况,根据Maven的最短依赖路径原则,会使用spring-core4.0.8
当在启动项目的时候会报错:
项目报错
- 不同的jar包,出现相同的类路径,此时JVM运行时会不知道执行哪个类,会报 java.lang.AbstractMethodError: javax.xml.parsers.DocumentBuilderFactory.setFeature(Ljava/lang/String;Z)V类似运行时异常。
- 在运行期,很有可能出现依赖A在执行过程中调用C(1.0)以前有但是升级到C(1.1)就缺失的类c,导致运行期失败,出现很典型的依赖冲突时的NoClassDefFoundError错误。
- 如果是升级后出现原有的方法被修改而不存在的情况时,就会抛出NoSuchMethodError错误。
解:
-
首先可以借助Maven查看依赖的依赖树来分析一下:手动:mvn dependency:tree,或者使用IDEA的Maven Helper插件Dependency Analyzer插件来可视化地分析依赖关系,或者 mvn dependency:tree -Dverbose查看依赖树。这个过程后可以明确哪些dependency引入了可能会冲突的依赖。
analyzer解决冲突 -
Maven Helper插件就找到冲突jar包,然后在对应标红版本的jar包上面点击execlude,就可以将该jar包排除出去。
dependencytree -
使用ctrl+shift+alt+n 查找类路径所在的jar包,把对应的jar包在pom中排除。
其他解决方案:
①. 统一版本:为jar包指定一个版本,所有用到的都会是这个版本。操作如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
统一配置:
<properties>
<spring.version>4.1.1.RELEASE</spring.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
②. 排除加载:就是在别的用到这个jar包的地方加上说明,告诉它不用自己加载依赖用别人的。 如下: 如果我们不想通过 A->B->C>D1 引入 D1 的话,那么我们在声明引入 A 的时候将 D1 排除掉 举个例子:将 zookeeper 的 jline 依赖排除
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.1</version>
<exclusions>
<exclusion>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
</exclusion>
</exclusions>
</dependency>
网友评论