无涯

无所谓无 无所谓有

Maven依赖冲突

什么是Maven依赖冲突

我相信你在开发中一定碰到过下面这些情况,尤其是在变更maven依赖后

  1. 代码编写完成,启动报错java.lang.NoSuchMethodException,但是你检查了一圈发现IDE正确识别到了有这个方法
  2. 代码编写完成,启动报错java.lang.ClassNotFoundException,同样,IDE编辑器爷识别到有这个类
  3. 再或者,启动不报错,运行时,当调用到某给方法或者类时,出现上面两种异常

以上三种情况,大多数原因都是依赖冲突导致的。

依赖冲突就是maven依赖中存在如下情况:

  • 一个依赖同时存在多版本
  • maven在打包时只会选取其中一个版本,遵循最短路径原则。
  • 如果你的应用运行在某些其他“容器”里面,例如Spark等可能依赖会和“容器”本身本来就存在的依赖冲突。

所以,如果你运气好,maven取到的一个版本恰好能满足其他代码的依赖调用,那就不会报错。

但是大多数情况就是由于取到的版本不对出现依赖缺失报错问题。

如何解决依赖冲突

前面我们提到,一个依赖同时存在多版本导致冲突,那我们要解决的就是保证工程依赖中只保留一个唯一的依赖版本。

看个例子

modelA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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依赖,但是他们的版本并不一致,这就产生冲突了。看图

image-20211020144444938

两种解决方案

排除其中一个依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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

点击安装:https://plugins.jetbrains.com/plugin/7179-maven-helper

image-20211020150519041

这个插件可以很方便定位冲突。