掘金 后端 ( ) • 2024-03-23 08:01
JAR

在项目开发中,多少都会遇到Maven的jar包冲突问题,如:

  • 引入新包后报了NoSuchMethodError
  • 很多个依赖都引入了不同版本的jar包A,造成A的版本不统一。

要解决jar包冲突的问题,就需要先搞清楚Maven中的依赖传递原则以及造成jar包冲突背后的原理

Maven中的依赖传递原则

Maven中的依赖传递原则为:最短路径优先原则,最先声明优先原则。

1. 最短路径优先原则

举例:假设工程引入了jar包AB,它们都依赖了Z这个jar包:

A --> X --> Y --> Z(2.5)

B --> X --> Z(2.0)

则最终Z(2.0) 版本生效,因为它的路径更短。

2. 最先声明优先原则

举例:假设工程引入了jar包AB,它们都依赖了Z这个jar包,在工程pom.xml文件中,A先于B声明:

A --> Z(2.5)

B --> Z(2.0)

则最终Z(2.5) 版本生效,因为这里A最先声明,所以传递过来的Z选用2.5版本。

Maven中Jar包冲突原理

根据上面的举例,假设工程中引入了jar包AB,它们都依赖了Z这个jar包:

A --> X --> Y --> Z(2.5)

B --> X --> Z(2.0)

根据最短路径优先原则,最终依赖的是Z(2.0) 版本生效。

如果在Y包中使用了Z包2.5版本中新的method,当运行到这段逻辑时,就会报NoSuchMethodError

原因是: Y包本来依赖Z的2.5版本,但因为jar包冲突,Maven根据最短路径优先原则选择了Z的2.0版本,而Z的2.0版本中没有这个新的method,导致出错。

注意: 不是所有冲突都会引起运行异常,只有高版本jar包向下不兼容,或者新增了某些低版本没有的API,则有可能导致冲突出错。

Maven冲突检测

1. 在IDEA安装Maven Helper插件

image.png

2. 使用Maven Helper插件进行jar包冲突检测

1)通过全部依赖树或列表,标亮的即存在jar包冲突,选中则可以查看jar包冲突具体版本

image.png

上图示例,表明log4j这个jar包,有2个传递依赖,分别为1.2.14版本1.2.16版本,冲突描述为:

omitted for conflict with 1.2.14. --- 由于与1.2.14版本冲突而被省略

2)搜索jar包检测冲突

image.png

3)通过mvn命令检测冲突

命令为:mvn dependency:tree -Dverbose

注意:不要省略-Dverbose参数,否则不会显示被忽略的包

解决冲突

1. 排除法

选中冲突的jar包,点击右键,选择Exclude,即可排查掉此jar包

image.png

2. 版本锁定法

如果很多个依赖都传递了jar包A,涉及了很多个版本,但只想指定一个版本,用排除法一个个去exclude太麻烦。

版本锁定法: 公司项目一般都会有父级pom文件,想指定哪个版本,只需在项目的父级pom中定义即可,其他子module的pom中,只引入依赖,不需要指定版本。

举例:

在项目父级pom中定义要依赖的mapstruct版本,如下:

<!-- 父级pom文件 -->
<dependencyManagement>
    <dependencies>
        <dependency>  
            <groupId>org.mapstruct</groupId>  
            <artifactId>mapstruct</artifactId>  
            <version>1.3.0.Final</version>  
        </dependency>
    </dependencies>
</dependencyManagement>

在其他子module的pom中,只引入依赖,不需要再指定mapstruct的版本,如下:

<!-- 子module的pom文件 -->
<dependencies>
    <dependency>  
        <groupId>org.mapstruct</groupId>  
        <artifactId>mapstruct</artifactId>  
    </dependency>
</dependencies>

注意: 版本锁定并不排除jar包,而是显示上把所有版本不一致的jar包变成统一一个版本。

总结

  • 尽量在父级pom中定义<dependencyManagement>来管理和统一依赖版本。
  • 对外提供的jar包,尽量不要传递依赖不必要的jar包。
  • 使用maven命令来检测分析依赖:
    • 使用mvn dependency:tree -Dverbose命令来检测jar包冲突。
    • 使用mvn dependency:analyze-only命令来检测声明了但没有被使用的依赖,尽量去掉。
    • 使用mvn dependency:analyze-duplicate命令来分析重复定义的依赖,清理掉重复定义的依赖。

参考文章:https://segmentfault.com/a/1190000023446358