在maven中如何解决依赖冲突?

1,023 阅读2分钟

世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程。

我们在做项目时,导入的jar包经常遇到依赖冲突的问题,如何解决呢?这里提供了5种解决方案。

  1. 先声明者生效
    比如引入了两个netty的jar包依赖
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.49.Final</version>
</dependency>

<dependency>
    <groupId>io.netty</groupId>
     <artifactId>netty-all</artifactId>
     <version>4.1.48.Final</version>
 </dependency>

以上版本分别为4.1.49.Final与4.1.48.Final,如果用集成开发工具查看依赖,会发现显示的版本是4.1.49.Final,这是为什么呢?原因很简单4.1.49.Final版本的netty放在了4.1.48.Final版本的前面;如果反过来放,查看版本号时就变成4.1.48.Final了。所以如果有两个不同版本相同功能的jar依赖,想要哪个版本的jar生效,就把它放在另一个版本jar依赖的前面。

  1. 最短路径者生效
    同样有两个jar依赖:
<dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>  
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.3</version>
</dependency>

spring-boot-starter-web中包含依赖servlet-api,并且版本号为3.1,我们在它后面又加了一个servlet-api的依赖,如果去查看的话,servlet-api依赖的版本号会是多少呢?是2.3。为什么呢?这就是最短路径生效。版本为3.1的servlet-api确实在版本号为2.3的servlet-api的前面,但是它没有明确声明,是隐含在spring-boot-starter-web依赖中的,而servlet-api 2.3版本是明确声明出来的,在依赖树中依赖路径相对更近,所以servlet-api 2.3版本生效。

  1. 依赖排除
    这个大家比较熟悉了,通过exclution排除冲突的jar依赖。
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
     <exclusions>
         <exclusion>
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
         </exclusion>
     </exclusions>
 </dependency>

maven中有一个命令: mvn denpendency: tree
可以用来查看maven依赖树,以查找要排除冲突的jar依赖。

  1. 版本锁定
    使用dependencyManagement指定版本:
<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.1.RELEASE</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

以上指定spring-boot-*的版本号为2.3.1。这也是一种比较推荐的版本管理方式。

  1. 域指定为provided
    有时在maven打包时会出现冲突,那么provided就派上用场了,provided指定的依赖范围只有编译与测试,没有运行时。所以在打包时指定了provided的依赖包是不会被打进去的,这样可以避免与本地包的冲突。实现如下:
<dependency>
   <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.49.Final</version>
    <scope>provided</scope>
</dependency>