本文概览:介绍了版本冲突是什么,如何解决和避免。
1 何为依赖版本冲突
比如项目直接依赖a和b,这两包都依赖c。我们在上线时,假设d模块代码用到了C2.0的代码,修了d中c的版本号为2.0,,此时在项目依赖如下:
- 项目->a->c(1.0),
- 项目->b->d>->c(2.0),
在编译阶段是没有问题的,因为a和d都是独立jar,不参与项目的编译了,所以在编译阶段不会报错,但是在运行阶段会存现错误,因为编译时是加载的c1.0的版本,而d需要c2.0。这就是版本冲突。产生版本冲突原因:通过依赖传递,项目所依赖的jar可能有多个版本,但是只会保留一个版本。
2 maven选择jar版本策略
当在项目中依赖的一个jar存多个版本时,此时选择策略是最短路径。在项目依赖如下,此时项目中依赖的c有1.0和2.0有两个版本,此时根据最短路径会选择1.0。
- 项目->a->c(1.0),
- 项目->b->d>->c(2.0),
假设在路径相同时,如下,
- 项目->a->c(1.0),
- 项目->b->c(2.0),
此时早期版本是随机选择一个版本,maven2.0.9开始依赖于maven依赖顺序,如下,此时a依赖早于b依赖先被引用,所以此时会加载c2.0。
1 2 3 4 5 6 7 8 9 10 11 12 |
<depencies> <dependency> <groupId>xxx</groupId> <artifactId>a</artifactId> <version>xx</version> </dependency> <dependency> <groupId>xxx</groupId> <artifactId>b</artifactId> <version>xx</version> </dependency> <depencies> |
通过上面的覆盖策略,理解了自己项目中遇到一个依赖问题,如下app-service依赖关系。
- app-service->base-service-sdk>core-sdk(2.0)
- app-service->corse-sdk(1.0)
我们修改了base-service-sdk的core-sdk的版本号为2.0,在编译时,没有报错,但是在运行app-service会出现错误,因为此时app-service在编译打包时加载了c-sdk的 1.0,而运行时base-model中某些方法依赖c-sdk2.0。为了解决这个问题我们可以升级下app-service-c-sdk的版本为2.0。
3 冲突解决
解决冲突目的是:保证依赖的jar是自己想要的版本。有三种方式:
方式1:覆盖方式。这是最高效快速解决冲突方式。
还是上面的例子,项目依赖如下:
- 项目->a->c(1.0),
- 项目->b->d>->c(2.0),
此时为了使用到c(2.0),可以直接在项目的pom.xml中直接引入c2.0,即此时依赖如下:
- 项目->c(2.0) ##直接覆盖,根据路径最短原则此时会选择c.20版本
- 项目->a->c(1.0)
- 项目->b->d>->c(2.0)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<depencies> <dependency> <groupId>xxx</groupId> <artifactId>a</artifactId> <version>xx</version> </dependency> <dependency> <groupId>xxx</groupId> <artifactId>d</artifactId> <version>xx</version> </dependency> <!--通过在根pom.xml 中覆盖的方式实现--> <dependency> <groupId>xxx</groupId> <artifactId>c</artifactId> <version>2.0</version> </dependency> <depencies> |
方式2 exclude。这是最常用的方式
还是上面的实例,项目依赖如下:
- 项目->a->c(1.0),
- 项目->b->d>->c(2.0),
此时可以通过exclude方式在a中排除掉c1.0,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<depencies> <dependency> <groupId>xxx</groupId> <artifactId>a</artifactId> <version>xx</version> <!--通过exclude方式实现--> <exclusions> <exclusion> <groupId>xxxx</groupId> <artifactId>c</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>xxx</groupId> <artifactId>d</artifactId> <version>xx</version> </dependency> <depencies> |
方式3 将版本的冲突的jar升级为相同的版本。
还是上面的实例,项目依赖如下:
- 项目->a->c(1.0),
- 项目->b->d>->c(2.0),
此时可以通过在a中奖c版本升级到2.0来解决。
4 冲突避免
冲突都是在编译时候无法发现,只有运行时,才可以发现,所以要在编译时期时期发现,有如下措施: 在引入一个新的包时,可以在打包完成之后,解压包看看这个jar的版本是不是自己想要的版本。 如果不是自己想要的jar,可以通过IDE插件 Dependency Analyzer来查看冲突的jar有哪些,通过覆盖或者exclude等手段保证依赖的包是自己的版本。