什么是Maven依赖冲突
我相信你在开发中一定碰到过下面这些情况,尤其是在变更maven
依赖后
- 代码编写完成,启动报错
java.lang.NoSuchMethodException
,但是你检查了一圈发现IDE正确识别到了有这个方法 - 代码编写完成,启动报错
java.lang.ClassNotFoundException
,同样,IDE编辑器爷识别到有这个类 - 再或者,启动不报错,运行时,当调用到某给方法或者类时,出现上面两种异常
以上三种情况,大多数原因都是依赖冲突导致的。
依赖冲突就是maven依赖中存在如下情况:
- 一个依赖同时存在多版本
- maven在打包时只会选取其中一个版本,遵循最短路径原则。
- 如果你的应用运行在某些其他“容器”里面,例如Spark等可能依赖会和“容器”本身本来就存在的依赖冲突。
所以,如果你运气好,maven取到的一个版本恰好能满足其他代码的依赖调用,那就不会报错。
但是大多数情况就是由于取到的版本不对出现依赖缺失报错问题。
如何解决依赖冲突
前面我们提到,一个依赖同时存在多版本导致冲突,那我们要解决的就是保证工程依赖中只保留一个唯一的依赖版本。
看个例子
modelA
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>modelA</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
</dependencies>
</project>
modelB
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>modelB</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
</dependencies>
</project>
modelC
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>modelC</artifactId>
<dependencies>
<dependency>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<artifactId>modelA</artifactId>
</dependency>
<dependency>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<artifactId>modelB</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
这里的关系是,modelA、modelB、modelC 都是demo的子模块,C依赖B和A。
B和C都引入了fastjson
依赖,但是他们的版本并不一致,这就产生冲突了。看图
两种解决方案
排除其中一个依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>modelC</artifactId>
<dependencies>
<dependency>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<artifactId>modelA</artifactId>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<artifactId>modelB</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
C依赖A的模块排除了fastjson
依赖,所以现在只存在B中依赖的fastjson
了。
这种方式一般适用于,引用别人的包,因为你改不了别人依赖的版本,只能进行手动排除,使用自己的版本。
统一版本
如果是你自己能控制引入的依赖,建议进行依赖统一,我们这里示例的A、B、C三个模块都有一个父模块,所以我我们可以将这种常用的依赖进行父模块管理,dependencyManagement
demo xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>modelA</module>
<module>modelB</module>
<module>modelC</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>demo</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<artifactId>modelA</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<artifactId>modelB</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
在进行父模块版本管理后,子模块再引用改依赖就不用指定版本了,默认使用依赖管理的版本。spring boot parent
就是如此的。
modelA
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>top.oneyoung.maven-conflict-demo</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>modelA</artifactId>
<dependencies>
<!--不用指定版本-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
</project>
工具推荐
如果你在使用IDEA
进行开发,不妨安装下这个插件 Maven Helper