NoSuchMethodError的常见原因和通用解决方式

news2025/7/6 5:27:25

目录

环境信息

问题描述

错误分析

解决方法

常见原因

1.第三方包,作用域不对导致应用没导入该包

2.编译时和运行时使用的版本不一样

3.JDK版本不一样

4.多个同路径、同名的类

        1.代码复制场景

        2.代码移动场景

排查步骤

附录

Maven仲裁机制:

JVM类加载机制


环境信息

        Spring Boot:2.0.8.RELEASE

        Spring Boot内置的tomcat:tomcat-embed-core 8.5.37

问题描述

        测试环境,部署打版之后,应用成功启动。可是在收到部分请求的时候,后端报错了,查看日志,发现出现了java.lang.NoSuchMethodError,具体是:

Caused by: java.lang.NoSuchMethodError: com.xxx.utils.IdMakerUtil.getInstance(JJJ)Lcom/x/utilxxs/IdMakerUtil;
    at com.xxx.framework.idgenerator.SnowflakeIdGenerator.<init>(SnowflakeIdGenerator.java:18)
    at com.xxx.utils.IdUtil.<clinit>(IdUtil.java:19)  at com.xxx.framework.web.interceptor.WebRequestBodyAdvice.afterBodyRead(WebRequestBodyAdvice.java:63)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyAdviceChain.afterBodyRead(RequestResponseBodyAdviceChain.java:100)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:208)
    at 

错误分析

          java.lang.NoSuchMethodError是一种运行时异常(runtime error),发生于一个方法,在编译的时候是存在的,在程序运行时不存在。java的垃圾处理器(GC)无法回收对象创建时申请的空间,有可能会造成OutOfMemoryError。

        在这次报错中,提示了找不到的方法是

com.xxx.utils.IdMakerUtil.getInstance(JJJ)Lcom/xxx/utils/IdMakerUtil;

类全路径是com.xxx.utils.IdMakerUtil,方法名是getInstance,(JJJ)代表该方法有三个参数,发生于com/xxx/utils/IdMakerUtil这个类。

        打开本地项目,应用正常启动,请求也能正常放回,不会报NoSuchMethodError。

但是仔细查看本地的IdMakerUtil.getInstance(),发现是个无参方法,和报错提示里使用的三个入参不一样,所以提示了NoSuchMethodError。本地的IdMakerUtil和测试环境的运行jar包里的IdMakerUtil是一样的,那么问题可能出现在调用该方法(IdMakerUtil.getInstance(x,x,x))的地方,即日志里提示的:

com.xxx.framework.idgenerator.SnowflakeIdGenerator.<init>(SnowflakeIdGenerator.java:18)

        仔细对比本地和运行jar包里的SnowflakeIdGenerator这个类,在A依赖包里,发现是一样的。但是,并没有在init初始化(构造方法里)调用IdMakerUtil.getInstance(x,x,x)

        本地和运行jar包里的SnowflakeIdGenerator:

        

        代码都一样,但是报错了,重点就是运行jar包里SnowflakeIdGenerator的构造方法里,调用了三个入参的IdMakerUtil.getInstance(x,x,x),和本地代码执行逻辑不一样

        由此可以推断,运行jar包使用的SnowflakeIdGenerator这个类,不是在A依赖包里的,而是另一个同路径、同名的类(com.xxx.framework.idgenerator.SnowflakeIdGenerator)!涉及到了JVM类加载机制,同路径、同名的类,只能加载一个。

        此时,想解决问题得找到实际使用的该SnowflakeIdGenerator类是在哪个jar包里,这时可以通过引入Arthas来查看。Arthas的sc命令,可以用来查看 JVM 已加载的类信息。具体的使用可以见官网。

sc | arthas (aliyun.com)

[arthas@2188]$ sc com.xxx.framework.idgenerator.SnowflakeIdGenerator
com.xxx.framework.idgenerator.SnowflakeIdGenerator
Affect(row-cnt:1) cost in 34 ms.
[arthas@2188]$ sc -d com.xxx.framework.idgenerator.SnowflakeIdGenerator
 class-info        com.xxx.framework.idgenerator.SnowflakeIdGenerator       
 code-source       file:/home/p05_dev/tfb-whole-biz-service-app/tfb-whole-biz-service-app-6.0.1-SNAPSHOT.jar!/BOOT-INF/lib/e-module-2.0.0-SNAPSHOT.jar!/
 name              com.xxx.framework.idgenerator.SnowflakeIdGenerator       
 isInterface      false
 isAnnotation      false                          
 isEnum            false                    
 isAnonymousClass  false
 isArray           false
 isLocalClass      false
 isMemberClass     false
 isPrimitive       false
 isSynthetic       false
 simple-name       SnowflakeIdGenerator
 modifier          public              
 annotation             
 interfaces             
 super-class       +-com.xxx.framework.idgenerator.AbstractIdGenerator      
                     +-java.lang.Object
 class-loader      +-org.springframework.boot.loader.LaunchedURLClassLoader@20a14b55
                     +-sun.misc.Launcher$AppClassLoader@18b4aac2                    
                       +-sun.misc.Launcher$ExtClassLoader@149b8519                  
 classLoaderHash   20a14b55            

Affect(row-cnt:1) cost in 53 ms.
[arthas@2188]$ 

可以看到,运行时使用的SnowflakeIdGenerator是在e-module-2.0.0-SNAPSHOT.jar包里,检查本地的代码,该包的源码里没有SnowflakeIdGenerator这个类,查看git历史记录发现,该类被移动位置了,从e-module移动到了A模块。但是e-module包没有发布到maven仓库里,测试环境打版的时候使用了旧的包。

解决方法

       发布e-module包到仓库里:mvn clean deploy

注意要先clean 再 deploy,其他同事应该是没有deploy,或者没先clean直接deploy导致发布失败。

        备注:公司是使用Jenkins来打版的,只是utils、framework框架基础包仅限于几个人修改,不开放给其他同事,修改了代码之后,需要手动在本地发布jar包到maven仓库。这个也是本次测试环境事故的一个原因。

        之前一个同事将SnowflakeIdGenerator从e-module包,移动到A包,并删除了构造函数里调用IdMakerUtil.getInstance地方,但是忘了将e-module包deploy到maven仓库,只将A包deploy上去。

常见原因

1.第三方包,作用域不对导致应用没导入该包

直接现象:解压运行时的jar包,找不到该方法所在的jar包。找不到class文件。

该方法位于第三方包内,而maven配置文件里,该包的作用域(scope)是provided时,程序打出的jar包是不包含该包的。

这里要理解scope里的compile、provided、runtime、test、system的区别

1.compile:(默认),编译、

2.provided:和compile很像,但是要求JDK或者应用所在的运行容器(比如tomcat、jetty)中包含该jar包。

3.runtime:运行时。意味着该jar包在编译期间不需要,但是在运行、测试期间需要。maven会在运行、测试的时候,将该jar包加入classpath里,编译的时候不会。

4.test:测试时。意味着该jar包只用于执行测试案例(src/test/java)的时候用到,比如测试包如JUnit,或者测试时要用的依赖包如IO包。

5.system:和provided很像,但是要求我们要手动提供该jar包,而永远不会去从maven仓库里查找该包。

6.import:用于jar类型(packaging)是pom,而且是在<dependencyManagement>域里。一般用于jar包管理里,用于声明会用到的依赖及其版本,编译、打包的时候不会真正的导入该包。其子包可以直接引入该包而不用指定版本号,这时才会真正的导入该包。

2.编译时和运行时使用的版本不一样

直接现象:解压运行时的jar包,找得到该方法所在的jar包。查看该jar包里的该方法,发现方法的参数、返回值等不一样。class版本不一样。

该方法所在的jar包,编译期间用的版本和运行时使用的版本不一样。

常见于公司内部的依赖包代码有更新,可是未发布到maven仓库,或者发布的时候没有先clean导致发布失败,造成线上环境使用的依赖包还是旧的依赖包。应该使用命令:mvn clean deploy部署

或者依赖里没指定jar包的具体版本号,间接依赖使用了旧的版本。

3.JDK版本不一样

直接现象:class版本不一样。

编译和运行使用不同版本的JDK,一般是本地编译的JDK版本比较高,线上环境运行的JDK版本比较低。

4.多个同路径、同名的类

直接现象:在提示的类路径(package)、类名里找得到指定的方法,而且方法的参数、返回值等 一模一样,可是还是提示NoSuchMethodError。

这时候可以换个思路来思考:既然在这个类里的这个方法是存在的,那么是不是运行的程序使用的根本不是该类?!

常见原因:

        1.代码复制场景

比如根据开源版本定制开发,添加了自定义内容,可是类的路径没有变,只是打成了新的jar包名。同时,还引入了开源版本包。JVM类加载器对于同一个类只会加载一次,实际加载的类和实际环境有关:Jar包依赖的路径、文件加载顺序等,和操作系统、环境里jar包的具体路径等有关,很难排查。

        2.代码移动场景

比如一个类,原本是在Ajar包里,由于重构、功能调整等原因,移动到了Bjar包里,并且改了方法的参数或返回值。部署的时候,Ajar包没有成功发布、打到运行jar包里,Bjar包成功发布并打到运行jar包里。这时候,Ajar包和Bjar包都存在该类(同名、同路径),只是两个类里的方法不一样。运行的时候,可能因为JVM类加载器加载顺序的不同,先加载了Ajar包里的类,这时候,就会出现NoSuchMethodError异常。

这种情况,是很难排查的,因为查看本地代码的时候,根据类路径、名称找到的该类是在Bjar包里的(因为A包里的该类已经删除掉,看不到了),而解压运行jar包里的Bjar包,会发现该类里的方法是存在的。而查找问题的人如果不是移动该类的开发人员,是很难知道A包里也可能有该类,运行的时候使用的是A包里的类(这时候,如果没有抛出NoSuchMethodError异常,即没有改方法参数,只是改了里面的逻辑,那么更难意识到这里出现了问题!!!)。

排查步骤

1.解压运行jar包,查看NoSuchMethodError提示的报错类,看该类是否有该方法(参数也一样);

2.如果没有该方法(参数也一致),如果该类是公司内部开发的类,确认环境打版用的分支里是否提示没有的方法。如果有,那么是打版问题,将该类所在的包打版上去(根据实际情况,是手动deploy到maven仓库还是直接Jenkins打版、等等);

3.如果没有该方法(参数也一致),如果该类是第三方包里的类,确认下运行jar包里该类对应的jar包版本是否和本地是一样的(即是否是我们想要的版本)。如果版本不一致,那么分析运行环境里使用到该版本的原因(Maven冲突、仲裁等等,比如间接依赖,可以看附录部分);

4.如果该方法(参数也一致),那么查看异常日志调用该方法的地方(如本次事故里的SnowflakeIdGenerator.<init>构造方法),和环境打版用的分支里进行对比。如果代码不一致,那么进入2、3步骤。如果代码一致,但是和实际运行时调用的该方法(如此次的IdMakerUtil.getInstance(JJJ))不一致,那么可以确定实际运行时用的SnowflakeIdGenerator类和我们代码里的SnowflakeIdGenerator类不是同一个。可以通过Arthas的sc实时监控查看使用的具体信息(参考错误分析里的做法)

附录

Maven仲裁机制:

安全同学讲Maven间接依赖场景的仲裁机制-阿里云开发者社区 (aliyun.com)

Maven仲裁机制原则

1.依赖竞争时,越靠近主干的越优先。

2.单颗树在依赖在竞争时(dependencies)(注意:不是dependencyManagement里的dependencies):

当deep=1,即直接依赖。同级是靠后优先。

当deep>1,即间接依赖。同级是靠前优先。

3.单颗树在依赖管理在竞争时(注意:是dependencyManagement里的dependencies)是靠前优先的。

4.maven里最重要的2个关系,分别是继承关系和依赖关系。我们所有的规律都应该只从这2个关系入手。

下图中分别是2个子pom文件(方块代表依赖的节点,A-1 表示A这个节点使用的是1版本,字母代表节点,数字代表版本)。

左边这个子pom生成的树依赖了 D-1,D-2和D-5。满足依赖竞争原则1,即越靠近树的左侧越优先的原则,所以D-5会竞争成功。

但是B-1和B-2同时都位于树的同一深度,并且深度为1,由于B-2更加靠后,所以B-2会竞争成功。

右边的子pom生成的树依赖了 D-1和D-2,并且位于同一深度,但由于D-1和D-2是属于间接依赖的范围,deep大于1,所以是靠前优先,那么也就是D-1会竞争成功。

JVM类加载机制

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

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

相关文章

为啥这么人选择iPhone

01.听音乐&#xff08;10元/月&#xff09; 歌曲很全 多个终端支持 果子自带的Music app 在那个设备都可以使用&#xff0c; 包括MacBook Pro,iPhone&#xff0c;iPad&#xff0c;iwatch等 02.周边配件方便购买 03.遇到问题好解决 04.使用稳定&#xff0c;不会有广告&#x…

MySQL海量数据优化(理论+实战) 吊打面试官

一、准备表数据 咱们建一张用户表&#xff0c;表中的字段有用户ID、用户名、地址、记录创建时间&#xff0c;如图所示 ​OK&#xff0c;接下来准备写一个存储过程插入一百万条数据 CREATE TABLE t_user (id int NOT NULL,user_name varchar(32) CHARACTER SET utf8 COLLATE ut…

[附源码]Python计算机毕业设计防疫物资捐赠系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

Vue组件化编程开发

目录 一.模块 二.组件 &#xff08;快捷键< 回车 生成单组件模板&#xff09; 三.非单文件组件 四.单文件组件: 首先理解模块和组件的基本概念: 一.模块 1.理解:向外提供特定功能的js程序&#xff0c;一般就是一个js文件 2.为什么: js文件很多很复杂 3.作用:复用js, 简…

Mybatis-Plus+SpringBoot结合运用

目录 前言 一、创建Maven项目导入相关的依赖 二、在resources添加日志和连接数据库 1.日志文件(log4j.properties) 2.连接数据库&#xff08;application.properties&#xff09; 三、编写pojo &#xff08;注解编写get/set/tostring&#xff09; 四、UserMapper编写继承…

Fragment的生命周期

文章目录Fragment的生命周期Fragment的状态和回调运行状态暂停状态停止状态销毁状态回调方法附加的回调方法onAttach()onCreateView()onActivityCreated()onDestroyView()onDetach()Fragment完整的生命周期图Fragment的生命周期 和Activity一样,Fragment也有自己的生命周期,并…

c++实现图书管理系统v1.0

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录系统要求功能1.首页2.退出系统3.添加图书4.删除书籍5.查找书籍6.修改书籍信息7.显示所有图书8.查看书籍是否在书架上总代码收获系统要求 用c实现一个可以增删改查的…

商城项目环境准备 — docker安装kinaba和配置ik中文分词器

一、拉取kinaba镜像 docker pull kinaba:7.12.1二、启动kinaba容器 docker run -d \ --name kibana \ -e ELASTICSEARCH_HOSTShttp://es:9200 \ --networkes-net \ -p 5601:5601 \ kibana:7.12.1三、访问 输入http://ip:5601 ip&#xff1a;服务器端口 四、安装ik分词器 …

研究光度立体法阶段性小结和优化(可20ms获取4个2500*2000灰度图的Normal Map)。...

这个东西是我接触的第一个非2D方面的算法&#xff0c;到目前为止其实也没有完全搞定&#xff0c;不过可能短时间内也无法突破。先把能搞定的搞定吧。 这个东西也有一大堆参考资料&#xff0c;不过呢&#xff0c;搜来搜去其实也就那些同样的东西&#xff0c;个人觉得就属这个文章…

Java自幂数计算及其算法改进

文章目录1. 自幂数2.自幂数的个数3. 常规自幂数计算方法4.算法代码改进1. 自幂数 如果在一个固定的进制中&#xff0c;一个n位自然数等于自身各个数位上数字的n次幂之和&#xff0c;则称此数为自幂数。 例如&#xff1a;在十进制中&#xff0c;153是一个三位数&#xff0c;各个…

计算机网络4小时速成:网络层,虚电路和数据包服务,ipv4,ABC类地址,地址解析协议ARP,子网掩码,ICMP忘记控制报文协议,路由选择协议,路由器

计算机网络4小时速成&#xff1a;网络层&#xff0c;虚电路和数据包服务&#xff0c;ipv4,ABC类地址&#xff0c;地址解析协议ARP&#xff0c;子网掩码&#xff0c;ICMP忘记控制报文协议&#xff0c;路由选择协议&#xff0c;路由器 2022找工作是学历、能力和运气的超强结合体…

新闻管理系统(SpringBoot+Vue)

商丘工学院新闻网 1、前言 sqgxy-xxydz-news是在大四参加的web大赛的一个项目&#xff0c;与我的队友协同开发&#xff0c;在此过程中收获颇多。 2、介绍 商丘工学院新闻官网&#xff08;信息与电子工程学院&#xff09;包括前台新闻展示系统及后台管理系统&#xff0c;基于Sp…

九种常见UML图

我常用的UML图是 类图、用例图、序列图、状态图这4种。 1、类图 类图是面向对象系统建模最常见的图&#xff0c;是定义其他图的基础 类图主要用用来显示系统中的类&#xff0c;接口以及它们之间的静态结构和关系的一种静态模型 类图显示 集合的类、接口、关联、协作和约束&…

Shiro笔记03-与Spring Boot整合

框架整合 创建模块 创建一个Maven工程 添加依赖 <?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…

生还是不生? SpringBoot3 版本有起飞前兆,最小依赖Java17!

一直以来&#xff0c;Java8都是Java社区心头的痛。因为它代表着以稳定性为主的企业管理层&#xff0c;与拥抱变化为主的底层码农层之间的、爱的魔力拉锯战。 不生&#xff01;少生&#xff01;成为各大厂心照不宣的选择。 现在&#xff0c;这种平衡或将打破。因为Java届的霸主…

Python3编程基础-变量与计算器

变量与计算器 简单计算器 下面来做一个简单计算器&#xff0c;完成普通计算器功能。 打开IDlE&#xff0c;输入以下脚本进行计算。 >>> 34 7 >>> 6-(8*2) -10 >>> (5*234)*(45) 396 >>> 每一行都是一个Python语句&#xff0c;如果可能的…

Java并发-为什么主线程结束了,程序却没有关闭呢?

守护线程与用户线程的定义及区别 Java 中的线程分为两类&#xff0c;分别为 daemon 线程&#xff08;守护线程&#xff09;和 user 线程&#xff08;用户线程&#xff09;。 在 JVM 启动时会调用 main 函数&#xff0c; main 函数所在的线程就是一个用户线程&#xff0c;其实…

TCP协议灵魂之问

先亮出这篇文章的思维导图: TCP 作为传输层的协议&#xff0c;是一个软件工程师素养的体现&#xff0c;也是面试中经常被问到的知识点。在此&#xff0c;我将 TCP 核心的一些问题梳理了一下&#xff0c;希望能帮到各位。 001. 能不能说一说 TCP 和 UDP 的区别&#xff1f; 首…

四十分钟带你玩儿转Python-OpenCV(一)

14天学习训练营导师课程&#xff1a; 李宁《Python Pygame游戏开发入门与实战》 李宁《计算机视觉OpenCV Python项目实战》1 李宁《计算机视觉OpenCV Python项目实战》2 李宁《计算机视觉OpenCV Python项目实战》3 OpenCV是一个基于BSD许可&#xff08;开源&#xff09;发行的跨…

基于keras 卷积神经外网络搭建的手写数字识别 完整代码+数据可直接运行

项目介绍: 适合新手入门学习代码数据很简洁 上结果: 主要的卷积神经网络: 卷积是指在滑动中提取特征的过程,可以形象地理解为用放大镜把每步都放大并且拍下来,再把拍下来的图片拼接成一个新的大图片的过程。 2D卷积是一个相当简单的操作: 我们先从一个小小的权重矩阵…