JVM记一次java.lang.NoSuchMethodError问题排查过程



项目场景:

    最近在看深入理解JAVA虚拟机,很巧,这两天正好遇到一个相关的问题,记录一下排查过程和问题产生的原因 ,希望帮助到看这篇文章的朋友。NoSuchMethodError问题是由于系统开发补丁引起的




问题描述:

系统日志出现NoSuchMethodError

java.lang.NoSuchMethodError: com.star.sms.richclient.businessquery.form.ProductInfoView.getProduct()Lcom/star/sms/model/product/core/catalog/AbstractProduct;
at com.star.sms.richclient.businessquery.form.ProductSelector.getSelectObject(ProductSelector.java:43)
at com.star.common.swing.selection.JSelectionPanel$MyDialog.onFinish(JSelectionPanel.java:431)
at org.springframework.richclient.dialog.ApplicationDialog$1.doExecuteCommand(ApplicationDialog.java:343)
at org.springframework.richclient.command.ActionCommand.execute(ActionCommand.java:188)
at org.springframework.richclient.command.ActionCommand$1.actionPerformed(ActionCommand.java:123)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)




原因分析:

JVM加载类的顺序是先加载生效, 即有多个JAR里都有A类, 那么最先加载的A类生效,后加载的不生效,所以项目中我们通过对补丁包命名和版本控制的方式实现优先加载补丁Jar包里的类,通过这种方式实现修正系统中的程序问题。 例如 : 补丁包修改了Product类,那么部署补丁后JVM会加载补丁补丁包里修改后的Product类, 原工程Jar包里的Product代码不生效

现场出现问题后本地环境测试不能复现问题,起初很疑惑, 仔细分析问题出现时间时,发现出现问题前发布了一个补丁, 系统部署补丁后,程序中才报出了NoSuchMethodError错误, 所以怀疑和补丁有关,分析补丁代码,补丁中修改了ProductInfoView#getProduct方法,将返回值AbstractProduct 修改为 Object, 此方法被ProductSelector和PhysicProductSelector调用,因ProductSelector没有修改,所以补丁包中只构建了ProductInfoView和PhysicProductSelector,补丁包里没有ProductSelector.class

工程lib中ProductSelector 是之前构建的,构建时候ProductInfoView#getProduct方法返回值还是AbstractProduct, 使用javap命令查看ProductSelector的字节码,查看会发现字节码里invokevirtual指令处理的返回结果是AbstractProduct, 说明JVM解析ProductSelector.class的时候getSelectObject方法里引用的返回值是AbstractProduct,现在部署补丁后修改成Object ,造成方法不匹配,报错NoSuchMethodError

查看字节码见另一篇文章:使用Javap命令查看class文件的字节码




解决方案:

最终将ProductSelector重新编辑并构建到补丁包中后,问题解决, 对比字节码, 重新构建的字节码中返回值已经变成了Object

上一篇:JVM从虚拟机层面了解重载和重写

猜你喜欢

转载自blog.csdn.net/Beijing_L/article/details/120651819