使用maven管理jar包依赖时,可能会出现jar包版本冲突,不同版本的api调用方式可能不同,会出现NoSuchMethodError
和ClassNotFoundException
问题,甚至编译不通过,如:在common-lang3 的3.8.1版本中MethodUtils::invokeMethod(Object object, boolean forceAccess, String methodName, Object... args)
方法在3.4版本中不存在相同的函数签名方法,如果使用该api并依赖到了低版本会编译不通过。
maven具有依赖传递的特性,会生成一个Dependency Tree,首先看一下maven在多个不同版本的相同依赖时的仲裁策略:
- 查找
<dependencyManagement>
标签中指定的版本,存在则直接使用,不存在进入第2步 - 依据短路径优先原则,选择依赖树中路径最短的版本
- 依赖树路径长度相同,则按照第一声明优先原则选择版本,即选择pom中最先声明的版本
根据以上仲裁策略,版本冲突一般由以下几个必要条件:
- maven的依赖传递导致依赖树中出现一个jar包的多个版本
- maven仲裁机制选择错了依赖的版本
- 该jar包的不同版本之间类或方法不兼容,如函数签名变化
解决
首先定位冲突依赖,可使用以下方式:
- IDEA :Maven Helper 插件
- 命令行:
mvn dependency:tree -Dverbose
定位后,也有两类解决方式:
- 引用时使用
<exclusions>
标签排除冲突版本jar包 <dependencyManagement>
统一管理版本
其他
mvn dependency:analyze-only
检测那些声明了但是没有被使用的依赖mvn dependency:analyze-duplicate
分析重复定义的依赖