世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程。
我们在做项目时,导入的jar包经常遇到依赖冲突的问题,如何解决呢?这里提供了5种解决方案。
- 先声明者生效
比如引入了两个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依赖的前面。
- 最短路径者生效
同样有两个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版本生效。
- 依赖排除
这个大家比较熟悉了,通过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依赖。
- 版本锁定
使用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。这也是一种比较推荐的版本管理方式。
- 域指定为provided
有时在maven打包时会出现冲突,那么provided就派上用场了,provided指定的依赖范围只有编译与测试,没有运行时。所以在打包时指定了provided的依赖包是不会被打进去的,这样可以避免与本地包的冲突。实现如下:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.49.Final</version>
<scope>provided</scope>
</dependency>