简书网站开发,广州品牌网站建设 优美,html5 手机 手机网站,山西传染病最新消息今天#x1f680; 优质资源分享 #x1f680;
学习路线指引#xff08;点击解锁#xff09;知识定位人群定位#x1f9e1; Python实战微信订餐小程序 #x1f9e1;进阶级本课程是python flask微信小程序的完美结合#xff0c;从项目搭建到腾讯云部署上线#xff0c;打造一… 优质资源分享
学习路线指引点击解锁知识定位人群定位 Python实战微信订餐小程序 进阶级本课程是python flask微信小程序的完美结合从项目搭建到腾讯云部署上线打造一个全栈订餐系统。Python量化交易实战入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统
一、前言
什么是依赖冲突
依赖冲突是指项目依赖的某一个jar包有多个不同的版本因而造成了包版本冲突。
依赖冲突的原因
我们在maven项目的pom中 一般会引用许许多多的dependency。例如项目A有这样的依赖关系
A - C - X(1.0)
B - D - X(2.0)
X是A的传递性依赖但是两条依赖路径上有两个版本的X,那么哪个X会被Maven解析使用呢? 两个版本都被解析显然是不对的因为那会造成依赖重复因此必须选择一个。
至于怎么选肯定有它的规则下面会讲这里我们先假设最终引用的X(1.0)版本这样会不会有问题呢
当然会有的
1、你想如果B引用X(2.0)的新创建的类但因为最终被解析的是X(1.0)所以就会出现很典型的NoClassDefFoundError 或ClassNotFoundException依赖冲突报错。
2、如果B引用X(2.0)的新创建的方法但因为最终被解析的是X(1.0)所以就会抛出 NoSuchMethodError系统异常。
但换种角度如果最终解析的是X(2.0)就没问题了吗
那也不一定
1、如果X(2.0)删掉了X(1.0)的一些类但A已经引用了同样也会报NoClassDefFoundError或者ClassNotFoundException错误。
2、如果X(2.0)删掉了X(1.0)的一些方法但A已经引用了同样也会报NoSuchMethodError错误。
所以说具体问题还需具体分析到底采用哪个版本还需要看实际项目。也可能我们需要升级对应的A或者B的版本才能解决问题。
如果有两个版本的X,Maven是依据什么原则来选择解析哪个X呢?
二、maven依赖原则
maven依赖主要有两大原则
1、路径最近者优先
相同jar不同版本根据依赖的路径长短来决定引入哪个依赖。
举例
依赖链路一A - B - C - X(1.0)
依赖链路二F - D - X(2.0)
该例中X(1.0)的路径长度为3,而X(2.0)的路径长度为2,因此X(2.0)会被解析使用。依赖调解第一原则不能解决所有问题比如这样的依赖关系
A - B - Y(1.0)
c - D - Y(2.0)
Y(1.0)和Y(2.0)的依赖路径长度是一样的都为2。Maven定义了依赖调解的第二原则
2、第一声明者优先
在依赖路径长度相等的前提下在POM中依赖声明的顺序决定了谁会被解析使用顺序最前的那个依赖优胜。该例中如果A的依赖声明在C之前那么Y (1.0)就会被解析使用.
注意 子pom内声明的优先于父pom中的依赖。
三、如何排除依赖
我们先来解释下什么是传递性依赖
1、什么是传递性依赖
比如当我们项目中引用了A的依赖,A的依赖通常又会引入B的jar包B可能还会引入C的jar包。
这样当你在pom.xml文件中添加了A的依赖Maven会自动的帮你把所有相关的依赖都添加进来。
这里随便举一个例子比如我们为了实现导入导出功能我们可能会引入poi dependencygroupIdorg.apache.poigroupIdartifactIdpoi-ooxmlartifactIdversion3.10.1versiondependency
当你引入它的时候它其实还会映入其它jar包 dependenciesdependencygroupIdorg.apache.poigroupIdartifactIdpoiartifactIdversion3.10.1versiondependencydependencygroupIdorg.apache.poigroupIdartifactIdpoi-ooxml-schemasartifactIdversion3.10.1versiondependencydependencygroupIddom4jgroupIdartifactIddom4jartifactIdversion1.6.1versiondependencydependencies
就这样一层层的Maven会自动的帮你把所有相关的依赖都添加进来。传递性依赖会给项目引入很多依赖简化项目依赖管理但是也会带来问题。
最明显的就是容易发生依赖冲突。
2、如何排除依赖
关键字:exclusions
exclusions可以包含一个或者多exclusion子元素因此可以排除一个或者多个传递性依赖。
需要注意的是声明exclusion的时候只需要groupld和artifactld,而不需要要version元素。
示例 dependencygroupIdorg.apache.poigroupIdartifactIdpoi-ooxmlartifactIdversion3.10.1versionexclusionsexclusionartifactIdpoiartifactIdgroupIdorg.apache.poigroupIdexclusionexclusionsdependency
四、实例演示如何解决依赖冲突
我们先来复现因为依赖冲突导致项目报错的。
1、制造依赖冲突
在当前项目中我即引用了org.apache.poi又引用了com.alibaba的easyexcel。
pom文件如下: dependencygroupIdorg.apache.poigroupIdartifactIdpoi-ooxmlartifactIdversion3.10.1versiondependencydependencygroupIdcom.alibabagroupIdartifactIdeasyexcelartifactIdversion2.2.8versiondependency
然后在项目中添加如下代码:
SpringBootApplication
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);test();}public static void test() {//1.获取文件地址String fileName /excel/test.xlsx;//2、调用easyExcel里面的方法实现写操作EasyExcel.write(fileName, UserDto.class).sheet(某某报表).doWrite(new ArrayList());}
}
我们发现在SpringBoot启动的时候就报NoClassDefFoundError异常了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6yT7KBZT-1655313434420)(https://img2022.cnblogs.com/blog/1090617/202206/1090617-20220610154656255-1453028930.jpg)] 这就是依赖冲突导致的异常报错。
为什么会这样呢我们可以通过idea看下,打开maven菜单点击show dependencies。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rrABc0H7-1655313434423)(https://img2022.cnblogs.com/blog/1090617/202206/1090617-20220610154758772-1512354831.jpg)] 看到这里你大概就已经明白因为我当前的easyexcel引入的poi是3.17版本的但是因为根据maven依赖原则实际引入的poi版本确实是3.10.1版本的。
而DefaultTempFileCreationStrategy这个类在3.10.1这个版本并没有只有3.17版本才有所以报了这个错误这么一解释是不是都通了。
然后我们再来思考一个问题上面这个案例我们一眼就知道是最终应用哪个依赖里的哪个版本但如果你的项目中依赖许许多多的jar肉眼排查就没那么方便了这里推荐一个
Maven管理插件
2、Maven Helper插件分析jar包冲突
选择并下载插件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZfsFSGyh-1655313434424)(https://img2022.cnblogs.com/blog/1090617/202206/1090617-20220610154855238-1355549376.jpg)] 在pom文件中看到 dependency analyzer标志说明maven helper插件就安装成功了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N9ncay2C-1655313434425)(https://img2022.cnblogs.com/blog/1090617/202206/1090617-20220610154954775-1701444613.jpg)] 点击dependency analyzer之后就会进入到下面的页面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vmQRwB1h-1655313434426)(https://img2022.cnblogs.com/blog/1090617/202206/1090617-20220610155050180-103696186.jpg)] 从图中可以看出有哪些jar存在冲突存在冲突的情况下最终采用了哪个依赖的版本。标红的就是冲突版本白色的是当前的解析版本。
如果我们想保留标红的版本那我们可以标白区域右击选择排除(Exclude)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rUqHcTU4-1655313434427)(https://img2022.cnblogs.com/blog/1090617/202206/1090617-20220610155127183-14865086.jpg)] 然后我们再来看pom文件,发现在org.apache.poi中已经移除了poi了。 dependencygroupIdorg.apache.poigroupIdartifactIdpoi-ooxmlartifactIdversion3.10.1versionexclusionsexclusionartifactIdpoiartifactIdgroupIdorg.apache.poigroupIdexclusionexclusionsdependencydependencygroupIdcom.alibabagroupIdartifactIdeasyexcelartifactIdversion2.2.6versiondependency
我们再来看最终引用的poi版本是哪个
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PSRPKD3p-1655313434428)(https://img2022.cnblogs.com/blog/1090617/202206/1090617-20220610155127183-14865086.jpg)] 我们发现最终的版本最终已经变成3.17版本现在再启动就不会报错了成功解决依赖冲突问题。
五、总结
一般我们在解决依赖冲突的时候都会选择保留jar高的版本因为大部分jar在升级的时候都会做到向下兼容所以只要保留高的版本就不会有什么问题。
但是有些包版本变化大没法去做向下兼容高版本删了低版本的某些类或者某些方法那么这个时候就不能一股脑的去选择高版本但也不能选择低版本。
就比如下面这个案例
依赖链路一A - B - C - X(1.0)
依赖链路二F - D - X(2.0)
X(2.0) 没有对 X(1.0) 做向下兼容也就是说可能存在排除哪个都不行那怎么办我们只能考虑升级A的版本或者降低F的版本。比如A升级到A(2.0),使它依赖的X版本
变成X(2.0)这样的话就解决依赖冲突。
但话有说回来 A升级到A(2.0) 可能会影响许许多多的地方比如自己项目中代码是否需要改变或者因为 A升级到A(2.0) 导致 B和C的版本有所改变这些影响点都需要我
们去考虑的。所以说为什么说一个大型项目稳定后pom文件的升级是件繁琐的事情那是因为考虑的东西是在太多了稍有不慎就会因为依赖冲突而导致系统报错。
声明: 公众号如需转载该篇文章,发表文章的头部一定要 告知是转至公众号: 后端元宇宙。同时也可以问本人要markdown原稿和原图片。其它情况一律禁止转载
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xBZ1Kg5f-1655313434430)(https://img2020.cnblogs.com/blog/1090617/202111/1090617-20211125172727036-1937303215.gif)]