依赖冲突是什么
依赖冲突是
程序在编译或运行过程中,由于调用的方法不是期望依赖版本中的方法而导致编译失败或运行时异常。
依赖冲突通常表现为:
- 调用方法不存在
- 参数或返回类型不匹配
- 运行异常或返回值不符合预期
依赖冲突归因主要有两点:
- 依赖传递机制
依赖传递即:项目a直接依赖于b,b直接依赖c,那么传递的结果为a间接依赖于c,即a中也可以调用c的方法,不用再直接生命c。
项目往往有多个依赖,直接依赖与间接依赖间都难免有相同的依赖存在,而版本不同,maven为了保证只有一个依赖被解析使用,遵循2条基本原则:1. 路径优先 2. 声明优先。这样的择一去余的方法难免造成最终选择的依赖不是我们期望的依赖。当我们期望一个高版本而最终解析的是一个低版本时,那很可能造成我们调用的方法不存在等错误。 - 类加载机制
依赖冲突不仅发生在相同依赖不同版本间,也可能发生在不同依赖间,它们的特征是有相同的方法限定名(包名+类名+函数名),JVM的加载机制通常会保证同名类只会被加载一次,这样就可能导致拥有相同路径名的类(包名+类名)被加载一次,这样很可能需要的类没有被JVM加载。
避免及解决
- 解决
当遇到依赖冲突的时候,通常的做法是找到发生冲突的依赖来自哪个传递依赖,可以通过mvn默认集成插件执行mvn dependency:tree 或则通过idea的mvn helper插件分析,然后排除造成冲突的依赖或者在直接依赖中声明所需版本,如果没有必须指定特定版本,最好声明更新版本的依赖。 - 避免
为了尽量避免依赖冲突,尽量直接在pom中声明所需依赖;另外对项目依赖进行“瘦身”,尽量排除不需要的依赖。
实例介绍
最近用springboot + junit+jsonschema 写一个简单的接口测试框架时遇到依赖冲突,运行case 时载入jsonschema报错如下:
-
明确报错方法调用入口及被调用jar
idea追踪方法调用的地方,报错的方法来自com.github.everit-org.json-schema:org.everit.json.schema,显示调用的JSONObject类来自com.vaadin.external.google:android-json依赖,
-
明确期望被调用的jar
通过查看com.github.everit-org.json-schema:org.everit.json.schema的pom依赖,得知其依赖的json为org.json:json
-
明确被错误调用的jar来源
通过idea的maven helper插件得知com.vaadin.external.google:android-json来自spring-boot-start-test的间接依赖
依赖排除
在pom中排除依赖com.vaadin.external.google:android-json
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
- 验证及回归
重新运行测试用例,依赖冲突问题解决。注意:为了确认排除对依赖在项目其它地方没有应用,应该进行项目回归测试。