maven依赖冲突加载顺序与解决
依赖冲突加载顺序
介绍了项目中同时引用了相同依赖的不同版本,也就是冲突,maven 是如何选择的。了解了有助于解决项目中的依赖问题
先说结论:
- 直接依赖的会引用后申明的依赖
- 间接依赖使用路径长度最短的,如果长度一样,则优先申明的最终加载
- 有父 pom 的子 pom 中的会覆盖父 pom 的依赖版本
<dependencyManagement>
管理的版本,子模块 pom 中间接依赖的版本也被锁死
优先级(运行子 pom):<dependencyManagement>
> 子 pom(直接依赖) > 父 pom > 间接依赖
直接依赖
1 2 3 4 5 6 7 8 9 10 11 | <!-- 直接依赖 --> < dependency > < groupId >com.google.protobuf</ groupId > < artifactId >protobuf-java</ artifactId > < version >2.2.0</ version > </ dependency > < dependency > < groupId >com.google.protobuf</ groupId > < artifactId >protobuf-java</ artifactId > < version >3.19.4</ version > </ dependency > |
项目的 pom 文件直接引用依赖
结论:maven 会引用后申明的依赖
- 这种情况几乎不会有,谁会在一处同时申明2个相同依赖不同版本的依赖,假使出现了,了解即可。
间接依赖
假设 module-starter 的 pom 如下:
1 2 3 4 5 6 7 8 9 10 11 | < dependency > < groupId >com.meizi</ groupId > < artifactId >module4</ artifactId > < version >1.0-SNAPSHOT</ version > </ dependency > < dependency > < groupId >com.meizi</ groupId > < artifactId >module1</ artifactId > < version >1.0-SNAPSHOT</ version > </ dependency > |
module4 引用 protobuf-java:3.11.4
module1 引用 protobuf-java:2.2.0
最终使用的是 protobuf-java:3.11.4
结论:间接依赖使用优先申明的
假设 module-starter 的 pom 如下:
1 2 3 4 5 6 7 8 9 10 11 | < dependency > < groupId >com.meizi</ groupId > < artifactId >module2</ artifactId > < version >1.0-SNAPSHOT</ version > </ dependency > < dependency > < groupId >com.meizi</ groupId > < artifactId >module4</ artifactId > < version >1.0-SNAPSHOT</ version > </ dependency > |
module4 引用 protobuf-java:3.11.4 (路径长度1)
module2 引用 module3 引用 protobuf-java:3.19.4(路径长度2)
最终使用的是 protobuf-java:3.11.4
结论:间接依赖使用路径长度最短的,如果长度一样,则优先申明的最终加载
父 pom 中的依赖
父 pom 如下:
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 | <? 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" > < modelVersion >4.0.0</ modelVersion > < groupId >com.meizi</ groupId > < artifactId >learnmaven</ artifactId > < version >1.0-SNAPSHOT</ version > < packaging >pom</ packaging > < modules > < module >module1</ module > < module >module2</ module > < module >module3</ module > < module >module4</ module > < module >module-starter</ module > </ modules > < dependencies > < dependency > < groupId >com.google.protobuf</ groupId > < artifactId >protobuf-java</ artifactId > < version >3.11.4</ version > </ dependency > </ dependencies > </ project > |
module1 pom 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <? 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 >learnmaven</ artifactId > < groupId >com.meizi</ groupId > < version >1.0-SNAPSHOT</ version > </ parent > < modelVersion >4.0.0</ modelVersion > < artifactId >module1</ artifactId > < dependencies > < dependency > < groupId >com.google.protobuf</ groupId > < artifactId >protobuf-java</ artifactId > < version >2.2.0</ version > </ dependency > </ dependencies > </ project > |
结论:子 pom 中的会覆盖父 pom 的依赖版本
- 如果间接依赖和父 pom 中的依赖出现,以父 pom 优先
版本锁定 <dependencyManagement>
使用
如下在父 pom 申明:
1 2 3 4 5 6 7 8 9 10 | <!-- learnmaven 父pom--> < dependencyManagement > < dependencies > < dependency > < groupId >com.google.protobuf</ groupId > < artifactId >protobuf-java</ artifactId > < version >2.2.0</ version > </ dependency > </ dependencies > </ dependencyManagement > |
子模块 pom 可不用写版本
子模块中与 dependencyManagement 匹配的最小信息集是这四个 {groupId, artifactId, type, classifier},因为在大多数情况下都是 type=jar classifier=null,所以如果不写,maven默认,如果不是jar的需要指定。
1 2 3 4 5 | <!-- module-starter 子pom--> < dependency > < groupId >com.google.protobuf</ groupId > < artifactId >protobuf-java</ artifactId > </ dependency > |
子模块 pom 中间接依赖的版本也被锁死
1 2 3 4 5 6 7 8 9 10 11 12 | <!-- module-starter 子pom--> < dependency > < groupId >com.meizi</ groupId > < artifactId >module4</ artifactId > < version >1.0-SNAPSHOT</ version > </ dependency > < dependency > < groupId >com.meizi</ groupId > < artifactId >module3</ artifactId > < version >1.0-SNAPSHOT</ version > </ dependency > |
从可传播依赖并入的依赖的版本也受此限制。
依赖冲突解决
了解了依赖冲突加载顺序,一定程度上可以解决冲突。 由于没有依赖传播级数的限制,会有可能出现循环依赖。 所以有一些方式来限制依赖传播
依赖调解(最短路径)
最短路径
项目的依赖树最近的依赖
如下依赖:
会使用 D 1.0
,因为他的路径最短,如果你想使用 D 2.0
可以在 A 项目中直接添加 D 2.0
依赖,如下
版本锁定
即 <dependencyManagement>
,使用见上文
依赖作用域
即 <scope>
作用域,限制依赖传递和决定何时依赖包含在类路径中
提供如下选项:
- compile 默认,编译依赖项在项目的所有类路径中都可用。此外,这些依赖关系被传播到依赖的项目。
- runtime 在编译中不需要,在执行中需要
- test 表明该依赖在正常使用中不是必须的,并且仅在测试编译和执行阶段可用,这个作用域不是可传递的
- system 除了您必须提供显式包含它的JAR之外,此作用域与提供的作用域类似。工件总是可用的,不会在存储库中查找。
- provided 类似compile,表明这个依赖是提供的,在运行时会有外部提供(例如tomcat),仅在编译和测试,是不可传递的
- import 只用在pom的
<dependencyManagement>
部分,它指示该依赖项将被指定POM的<dependencyManagement>
部分中的有效依赖项列表所替换。
排除依赖
通过使用 exclusion
可以将不需要的依赖排除掉
1 2 3 4 5 6 7 8 9 10 11 | < dependency > < groupId >com.meizi</ groupId > < artifactId >module4</ artifactId > < version >1.0-SNAPSHOT</ version > < exclusions > < exclusion > < groupId >com.google.protobuf</ groupId > < artifactId >protobuf-java</ artifactId > </ exclusion > </ exclusions > </ dependency > |
此时,引入module4,将不会引入 protobuf-java
。
可选依赖
即 <optional>
,默认false不可选,可传播; true 可选,可认为是被排除了,不可传播
1 2 3 4 5 6 7 | < dependency > < groupId >com.google.protobuf</ groupId > < artifactId >protobuf-java</ artifactId > < version >3.11.4</ version > <!-- 默认false不可选,可传播; true 可选,可认为是被排除了,不可传播 --> < optional >true</ optional > </ dependency > |
如果想排除此依赖,也可将 optional 设置为 true
依赖管理
导入依赖
在大型项目中,很难通过继承管理所有依赖,因为 maven 是单继承的。
为了解决这个,项目可以从其他项目导入。通过申明一个 type 是 pom,scope 是 import 的工件
1 2 3 4 5 6 7 8 9 10 11 12 | <!-- learnmaven 父pom--> < dependencyManagement > < dependencies > < dependency > < groupId >io.netty</ groupId > < artifactId >netty-bom</ artifactId > < version >4.1.29.Final</ version > < type >pom</ type > < scope >import</ scope > </ dependency > </ dependencies > </ dependencyManagement > |
所有 netty-bom 中 dependencyManagement 所管理的都会被合并过来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <!-- learnmaven 父pom--> < dependencyManagement > < dependencies > < dependency > < groupId >io.netty</ groupId > < artifactId >netty-bom</ artifactId > < version >4.1.79.Final</ version > < type >pom</ type > < scope >import</ scope > </ dependency > < dependency > < groupId >io.netty</ groupId > < artifactId >netty-bom</ artifactId > < version >4.1.29.Final</ version > < type >pom</ type > < scope >import</ scope > </ dependency > </ dependencies > </ dependencyManagement > |
如上,4.1.79.Final 将被使用,因为他先申明
并且导入是递归的,例如,netty-bom 导入了另一个 pom,那么这个项目也会导入
到此这篇关于maven依赖冲突加载顺序与解决的文章就介绍到这了,更多相关maven依赖冲突内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!
相关文章
Java解析zip文件,并识别压缩包里面的文件转换成可操作的IO流方式
这篇文章主要介绍了Java解析zip文件,并识别压缩包里面的文件转换成可操作的IO流方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-08-08SpringBoot项目启动时增加自定义Banner的简单方法
最近看到springboot可以自定义启动时的banner,然后自己试了一下,下面这篇文章主要给大家介绍了SpringBoot项目启动时增加自定义Banner的简单方法,需要的朋友可以参考下2022-01-01SpringBoot自定义MessageConvert详细讲解
正在学习SpringBoot,在自定义MessageConverter时发现:为同一个返回值类型配置多个MessageConverter时,可能会发生响应数据格式错误,或406异常(客户端无法接收相应数据)。在此记录一下解决问题以及追踪源码的过程2023-01-01
最新评论