【Maven】Maven 基础教程(五): jar 包冲突问题

Maven 基础教程》系列,包含以下 5 篇文章:

  • Maven 基础教程(一):基础介绍、开发环境配置
  • Maven 基础教程(二):Maven 的使用
  • Maven 基础教程(三):build、profile
  • Maven 基础教程(四):搭建 Maven 私服 Nexus
  • Maven 基础教程(五): jar 包冲突问题

😊 如果您觉得这篇文章有用 ✔️ 的话,请给博主一个一键三连 🚀🚀🚀 吧 (点赞 🧡、关注 💛、收藏 💚)!!!您的支持 💖💖💖 将激励 🔥 博主输出更多优质内容!!!

Maven 基础教程(五): jar 包冲突问题

  • 8.jar 包冲突问题
    • 8.1 表现形式
      • 8.1.1 抛异常:找不到类
      • 8.1.2 抛异常:找不到方法
      • 8.1.3 没报错但结果不对
    • 8.2 本质
    • 8.3 解决办法
      • 8.3.1 IDEA 的 Maven Helper 插件
      • 8.3.2 Maven 的 enforcer 插件

8.jar 包冲突问题

编订依赖列表的程序员,初次设定一组依赖,因为尚未经过验证,所以确实有可能存在各种问题,需要做有针对性的调整。那么谁来做这件事呢?我们最不希望看到的就是:团队中每个程序员都需要自己去找依赖,即使是做同一个项目,每个模块也各加各的依赖,没有统一管理。那前人踩过的坑,后人还要再踩一遍。而且大家用的依赖有很多细节都不一样,版本更是五花八门,这就让事情变得更加复杂。

所以虽然初期需要根据项目开发和实际运行情况对依赖配置不断调整,最终确定一个各方面都 OK 的版本。但是一旦确定下来,放在父工程中做依赖管理,各个子模块各取所需,这样基本上就能很好的避免问题的扩散。

即使开发中遇到了新问题,也可以回到源头检查、调整 dependencyManagement 配置的列表,而不是每个模块都要改。

8.1 表现形式

由于实际开发时我们往往都会整合使用很多大型框架,所以一个项目中哪怕只是一个模块也会涉及到大量 jar 包。数以百计的 jar 包要彼此协调、精密配合才能保证程序正常运行。而规模如此庞大的 jar 包组合在一起难免会有磕磕碰碰。最关键的是由于 jar 包冲突所导致的问题非常诡异,这里我们只能罗列较为典型的问题,而没法保证穷举。

但是我们仍然能够指出一点:一般来说,由于我们自己编写代码、配置文件写错所导致的问题 通常能够在异常信息中看到我们自己类的全类名或配置文件的所在路径。如果整个错误信息中完全没有我们负责的部分,全部是框架、第三方工具包里面的类报错,这往往就是 jar 包的问题所引起的。

而具体的表现形式中,主要体现为 找不到类找不到方法

8.1.1 抛异常:找不到类

此时抛出的常见的异常类型:

  • java.lang.ClassNotFoundException:编译过程中找不到类。
  • java.lang.NoClassDefFoundError:运行过程中找不到类。
  • java.lang.LinkageError:不同类加载器分别加载的多个类有相同的全限定名。

我们来举个例子:

<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.x.x</version>
</dependency>

httpclient 这个 jar 包中有一个类:org.apache.http.conn.ssl.NoopHostnameVerifier。这个类在较低版本中没有,但在较高版本存在。比如:

jar 包版本是否存在
4.3.6
4.4

那当我们确实需要用到 NoopHostnameVerifier 这个类,我们看到 Maven 通过依赖传递机制引入了这个 jar 包,所以没有明确地显式声明对这个 jar 包的依赖。可是 Maven 传递过来的 jar 包是 4.3.6 版本,里面没有包含我们需要的类,就会抛出异常。

冲突 体现在:4.3.64.4 这两个版本的 jar 包都被框架所依赖的 jar 包给传递进来了,但是假设 Maven 根据 版本仲裁 规则实际采纳的是 4.3.6

版本仲裁:Maven 的版本仲裁机制只是在没有人为干预的情况下,自主决定 jar 包版本的一个办法。而实际上我们要使用具体的哪一个版本,还要取决于项目中的实际情况。所以在项目正常运行的情况下,jar 包版本可以由 Maven 仲裁,不必我们操心;而发生冲突时 Maven 仲裁决定的版本无法满足要求,此时就应该由程序员明确指定 jar 包版本。

  • 最短路径优先:在下图的例子中,对模块 pro25-module-a 来说,Maven 会采纳 1.2.12 版本。

在这里插入图片描述

  • 路径相同时先声明者优先:此时 Maven 采纳哪个版本,取决于在 pro29-module-x 中,对 pro30-module-ypro31-module-z 两个模块的依赖哪一个先声明。

在这里插入图片描述

8.1.2 抛异常:找不到方法

程序找不到符合预期的方法。这种情况多见于通过反射调用方法,所以经常会导致:java.lang.NoSuchMethodError

8.1.3 没报错但结果不对

发生这种情况比较典型的原因是:两个 jar 包中的类分别实现了同一个接口,这本来是很正常的。但是问题在于:由于没有注意命名规范,两个不同实现类恰巧是同一个名字。
在这里插入图片描述

具体例子是实际工作中遇到过:项目中部分模块使用 log4j 打印日志;其它模块使用 logback,编译运行都不会冲突,但是会引起日志服务降级,让你的 log 配置文件失效。比如:你指定了 error 级别输出,但是冲突就会导致 infodebug 都在输出。

8.2 本质

以上表现形式归根到底是两种基本情况导致的:

  • 同一 jar 包的不同版本

在这里插入图片描述

  • 不同 jar 包中包含同名类

这里我们拿 netty 来举个例子,Netty 是一个类似 Tomcat 的 Servlet 容器。通常我们不会直接依赖它,所以基本上都是框架传递进来的。那么当我们用到的框架很多时,就会有不同的框架用不同的坐标导入 Netty。可以参照下表对比一下两组坐标:

截止到 3.2.10.Final 版本以前的坐标形式从 3.3.0.Final 版本开始以后的坐标形式
org.jboss.netty netty 3.2.10.Finalio.netty netty 3.9.2.Final

但是偏偏这两个『不同的包』里面又有很多『全限定名相同』的类。例如:

org.jboss.netty.channel.socket.ServerSocketChannelConfig.class
org.jboss.netty.channel.socket.nio.NioSocketChannelConfig.class
org.jboss.netty.util.internal.jzlib.Deflate.class
org.jboss.netty.handler.codec.serialization.ObjectDecoder.class
org.jboss.netty.util.internal.ConcurrentHashMap$HashIterator.class
org.jboss.netty.util.internal.jzlib.Tree.class
org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap$Segment.class
org.jboss.netty.handler.logging.LoggingHandler.class
org.jboss.netty.channel.ChannelHandlerLifeCycleException.class
org.jboss.netty.util.internal.ConcurrentIdentityHashMap$ValueIterator.class
org.jboss.netty.util.internal.ConcurrentIdentityWeakKeyHashMap$Values.class
org.jboss.netty.util.internal.UnterminatableExecutor.class
org.jboss.netty.handler.codec.compression.ZlibDecoder.class
org.jboss.netty.handler.codec.rtsp.RtspHeaders$Values.class
org.jboss.netty.handler.codec.replay.ReplayError.class
org.jboss.netty.buffer.HeapChannelBufferFactory.class
......

8.3 解决办法

很多情况下常用框架之间的整合容易出现的冲突问题都有人总结过了,拿抛出的异常搜索一下基本上就可以直接找到对应的 jar 包。我们接下来要说的是通用方法。

不管具体使用的是什么工具,基本思路无非是这么两步:

  • 第一步:把彼此冲突的 jar 包找到。
  • 第二步:在冲突的 jar 包中选定一个。具体做法无非是通过 exclusions 排除依赖,或是明确声明依赖。

8.3.1 IDEA 的 Maven Helper 插件

这个插件是 IDEA 中安装的插件,不是 Maven 插件。它能够给我们罗列出来同一个 jar 包的不同版本,以及它们的来源。但是对不同 jar 包中同名的类没有办法。
在这里插入图片描述

然后基于 pom.xml 的依赖冲突分析,如下:
在这里插入图片描述
查看冲突分析结果:

在这里插入图片描述

8.3.2 Maven 的 enforcer 插件

使用 Maven 的 enforcer 插件既可以检测同一个 jar 包的不同版本,又可以检测不同 jar 包中同名的类。

这里我们引入两个对 Netty 的依赖,展示不同 jar 包中有同名类的情况作为例子。

<dependencies><dependency><groupId>org.jboss.netty</groupId><artifactId>netty</artifactId><version>3.2.10.Final</version></dependency><dependency><groupId>io.netty</groupId><artifactId>netty</artifactId><version>3.9.2.Final</version></dependency></dependencies>

然后配置 enforcer 插件:

<build><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-enforcer-plugin</artifactId><version>1.4.1</version><executions><execution><id>enforce-dependencies</id><phase>validate</phase><goals><goal>display-info</goal><goal>enforce</goal></goals></execution></executions><dependencies><dependency><groupId>org.codehaus.mojo</groupId><artifactId>extra-enforcer-rules</artifactId><version>1.0-beta-4</version></dependency></dependencies><configuration><rules><banDuplicateClasses><findAllDuplicates>true</findAllDuplicates></banDuplicateClasses></rules></configuration></plugin></plugins></pluginManagement>
</build>

执行如下 Maven 命令:

mvn clean package enforcer:enforce

部分运行结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/727836.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ · 代码笔记3 · 引用

目录 前言011引用初探_引用与普通变量012引用初探_引用作为函数参数013引用初探_引用作为函数返回值014引用初探_引用返回局部函数造成的错误015引用初探_多级引用020引用与指针递增的区别030const与引用040使用const限定的函数形参引用 前言 本笔记所涉及到的编程环境与 《C …

经典语义分割(二)医学图像分割模型UNet

经典语义分割(二)医学图像分割模型UNet 我们之前介绍了全卷积神经网络( FCN) &#xff0c;FCN是基于深度学习的语义分割算法的开山之作。 今天我们介绍另一个语义分割的经典模型—UNet&#xff0c;它兼具轻量化与高性能&#xff0c;通常作为语义分割任务的基线测试模型&#x…

opengl 学习(三)-----着色器

着色器 分类demo效果解析教程 分类 OPengl C demo #include "glad/glad.h" #include "glfw3.h" #include <iostream> #include <cmath> #include <vector>#include <string> #include <fstream> #include <sstream>…

苍穹外卖技术栈

Day5 Redis_Spring Data Redis使用方法 Spring Data Redis Spring Date Redis 是Spring的一部分&#xff0c; 对Redis底层开发包进行了高度封装&#xff0c;在Spring项目中&#xff0c;可以使用Spring Data Redis来简化操作。 操作步骤 导入Spring Data Redis 的maven坐标配置…

浮点数和定点数

前言 大家好我是jiantaoyab&#xff0c;这是我所总结作为学习的笔记第七篇,在这里分享给大家,还有一些书籍《深入理解计算机系统》《计算机组成&#xff1a;结构化方法》《计算机体系结构&#xff1a;量化研究方法》&#xff0c;今天我们来了解定点数和浮点数 定点数 BCD编码 …

JavaScript基础4之原型的原型继承、原型链和理解对象的数据属性、访问器属性

JavaScript基础 原型原型继承问题解决 原型链isPrototypeOf()Object.getPrototypeOf() 理解对象数据属性访问器属性 原型 原型继承 继承是面向对象编程的另一个特征&#xff0c;通过继承进一步提升代码封装的程度&#xff0c;JavaScript中大多是借助原型对象实现继承的特性。…

蜘蛛池是什么意思,怎么生成蜘蛛池

蜘蛛池是由自然界中的蜘蛛群落构成的一个小生态系统&#xff0c;也是身处自然界中的游客们可以在风雨中体验到最贴近自然气息的地方。 点开我主页面 Baidu蜘蛛的作用&#xff1a; 引蜘蛛逐渐收录&#xff0c;降权引蜘蛛可以疗伤&#xff0c;排名/收录不稳定&#xff0c;没有收…

【Linux篇】gdb的使用

&#x1f49b;不要有太大压力&#x1f9e1; &#x1f49b;生活不是选择而是热爱&#x1f9e1; &#x1f49a;文章目录&#x1f49a; 1. 背景知识2. 使用 1. 背景知识 1. 程序发布的方式有两种&#xff0c;debug模式和release模式 2. Linux下&#xff0c;gcc和g编译生成的可执行…

国家积极推进长城国家文化公园建设

长城脚下&#xff0c;文化绽放——国家积极推进长城国家文化公园建设 在中华大地的北方&#xff0c;横亘着一条巨龙&#xff0c;它见证着中华民族的沧桑岁月&#xff0c;承载着我们的民族记忆&#xff0c;它就是——长城。这座千年的雄关&#xff0c;不仅是中国的象征&#xf…

[Unity实战]使用NavMeshAgent做玩家移动

其实除了Character Controller, Rigidbody&#xff0c;我们还可以使用NavMeshAgent去做。这么做的好处是能避免玩家去莫名其妙的地方&#xff08;毕竟基于烘焙过的导航网格&#xff09;&#xff0c;一般常见于元宇宙应用和mmo。 根据Unity手册&#xff0c;NavMeshAgent 也有和…

学c++对Python有帮助吗?

学习C对Python编程确实有帮助&#xff0c;尽管这两种语言在许多方面有很大的不同。以下是学习C可能对Python编程产生帮助的几个方面&#xff1a; 理解底层概念&#xff1a;C是一种更接近硬件的编程语言&#xff0c;它要求程序员更深入地理解内存管理、指针、数据类型等底层概念…

Linux:文件权限详解及修改方法

文章目录 1、Linux文件权限1.1、如何查看到文件权限1.2、ll命令介绍 2、权限分类2.1、文件权限2.2、文件夹权限 3、权限修改3.1、修改文件/文件夹权限1&#xff09;chmod指令2&#xff09;chmod指令符号 3.2、修改文件/文件夹所属用户3.3、修改文件/文件夹所属群组 4、参考 1、…

AI产品摄影丨香水

AI电商产品拍摄丨&#xff08;可指定产品&#xff09; 均为概念图 可换产品 可指定产品&#xff0c;可换logo 工具&#xff1a;StartAI 搭配“手机摄影”风格使用效果更佳哦 咒语&#xff1a;anha perfume in bottle on stone surface, in the style of everyday american…

和为K的子数组

题目&#xff1a; 使用前缀和的方法可以解决这个问题&#xff0c;因为我们需要找到和为k的连续子数组的个数。通过计算前缀和&#xff0c;我们可以将问题转化为求解两个前缀和之差等于k的情况。 假设数组的前缀和数组为prefixSum&#xff0c;其中prefixSum[i]表示从数组起始位…

分段线性化问题探析

目录 1 使用0-1变量将分段函数转换为线性约束 2 连续函数采用分段线性化示例 3 matlab程序测试 4 matlab测试结果说明 5 分段线性化应用 1 使用0-1变量将分段函数转换为线性约束 2 连续函数采用分段线性化示例 3 matlab程序测试 clc;clear all; gn10;tn1; x_pfsdpvar(1, t…

vue3基础教程(3)——引入ui框架iview(viewui)

博主个人微信小程序已经上线&#xff1a;【中二少年工具箱】。欢迎搜索试用 正文开始 专栏简介1. 下载iview2.更新资源3.引入插件4.运行项目 专栏简介 本系列文章由浅入深&#xff0c;从基础知识到实战开发&#xff0c;非常适合入门同学。 零基础读者也能成功由本系列文章入门…

底层day2作业

思维导图 作业&#xff1a; 1.使用ADC采样光敏电阻数值&#xff0c;如何根据这个数值调节LED灯亮度 连接硬件&#xff1a;将光敏电阻与单片机的ADC引脚连接&#xff0c;将LED灯与单片机的PWM引脚连接。初始化&#xff1a;在程序中初始化ADC和PWM模块&#xff0c;并设置相应的…

大数据分析技术工程师CCRC-BDATE

大数据分析技术工程师介绍 大数据始于科技之美&#xff0c;归于创造价值。大数据时代&#xff0c;“谁用好数据&#xff0c;谁就能把握先机、赢得主动”。当下数据驱动的电信、社交媒体、生物医疗、电子政务商务等行业都在产生着海量的数据&#xff0c;随着大规模数据关联、交叉…

@ResponseStatus

目录 概述&#xff1a; 用途&#xff1a; 参数&#xff1a; 注意事项&#xff1a; 自定义异常类&#xff1a; 底层原理&#xff1a; 概述&#xff1a; 在 Spring MVC 中&#xff0c;我们有很多方法来设置 HTTP 响应的状态码其中最直接的方法&#xff1a;使用 ResponseSt…

K8S之实现业务的蓝绿部署

如何实现蓝绿部署 什么是蓝绿部署&#xff1f;蓝绿部署的优势和缺点优点缺点 通过k8s实现线上业务的蓝绿部署 什么是蓝绿部署&#xff1f; 部署两套系统&#xff1a;一套是正在提供服务系统&#xff0c;标记为 “绿色” &#xff1b;另一套是准备发布的系统&#xff0c;标记为…