1、前言
有时spring boot应用会遇到java.lang.NoSuchMethodError的问题,下面以具体的demo来说明怎样利用arthas来排查。
Demo: https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-NoSuchMethodError
2、在应用的main函数里catch住异常,保证进程不退出
很多时候当应用抛出异常后,进程退出了,就比较难排查问题。可以先改下main函数,把异常catch住:
public static void main(String[] args) throws IOException {try {SpringApplication.run(DemoNoSuchMethodErrorApplication.class, args);} catch (Throwable e) {e.printStackTrace();}// blockSystem.in.read();}
Demo启动之后,抛出的异常是:
java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationAwareOrderComparator.sort(Ljava/util/List;)Vat org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:394)at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:383)at org.springframework.boot.SpringApplication.initialize(SpringApplication.java:249)at org.springframework.boot.SpringApplication.<init>(SpringApplication.java:225)at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)at com.example.demoNoSuchMethodError.DemoNoSuchMethodErrorApplication.main(DemoNoSuchMethodErrorApplication.java:13)
显然,异常的意思是AnnotationAwareOrderComparator缺少sort(Ljava/util/List;)V这个函数。
3、安装arthas
参考:https://alibaba.github.io/arthas/install-detail.html
使用sc命令查找类所在的jar包
应用需要抛出了异常,但是进程还没有退出,我们用arthas来attach上去。比如在mac下面:
./as.sh
然后选择com.example.demoNoSuchMethodError.DemoNoSuchMethodErrorApplication进程。
再执行sc命令来查找类:
$ sc -d org.springframework.core.annotation.AnnotationAwareOrderComparatorclass-info org.springframework.core.annotation.AnnotationAwareOrderComparatorcode-source /Users/hengyunabc/.m2/repository/org/springframework/spring/2.5.6.SEC03/spring-2.5.6.SEC03.jarname org.springframework.core.annotation.AnnotationAwareOrderComparatorisInterface falseisAnnotation falseisEnum falseisAnonymousClass falseisArray falseisLocalClass falseisMemberClass falseisPrimitive falseisSynthetic falsesimple-name AnnotationAwareOrderComparatormodifier publicannotationinterfacessuper-class +-org.springframework.core.OrderComparator+-java.lang.Objectclass-loader +-sun.misc.Launcher$AppClassLoader@5c647e05+-sun.misc.Launcher$ExtClassLoader@689e3d07classLoaderHash 5c647e05Affect(row-cnt:1) cost in 41 ms.
可以看到AnnotationAwareOrderComparator是从spring-2.5.6.SEC03.jar里加载的。
4、使用jad查看反编绎的源代码
下面使用jad命令来查看AnnotationAwareOrderComparator的源代码
$ jad org.springframework.core.annotation.AnnotationAwareOrderComparatorClassLoader:
+-sun.misc.Launcher$AppClassLoader@5c647e05+-sun.misc.Launcher$ExtClassLoader@689e3d07Location:
/Users/hengyunabc/.m2/repository/org/springframework/spring/2.5.6.SEC03/spring-2.5.6.SEC03.jar/** Decompiled with CFR 0_132.*/
package org.springframework.core.annotation;import java.lang.annotation.Annotation;
import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;public class AnnotationAwareOrderComparator
extends OrderComparator {protected int getOrder(Object obj) {Order order;if (obj instanceof Ordered) {return ((Ordered)obj).getOrder();}if (obj != null && (order = obj.getClass().getAnnotation(Order.class)) != null) {return order.value();}return Integer.MAX_VALUE;}
}Affect(row-cnt:1) cost in 286 ms.
可见,AnnotationAwareOrderComparator的确没有sort(Ljava/util/List;)V函数。
5、排掉依赖,解决问题
从上面的排查里,可以确定
- AnnotationAwareOrderComparator来自spring-2.5.6.SEC03.jar,的确没有sort(Ljava/util/List;)V函数。
所以,可以检查maven依赖,把spring 2的jar包排掉,这样子就可以解决问题了。
6、总结
- 仔细看NoSuchMethodError的异常信息,了解是什么类缺少了什么函数
- 利用arthas来查找类,反编绎源码,确认问题
本文主要注重思路。很多时候,本地开发与服务器上可能存在差异,本地问题容易debug,远程的虽然也可以远程debug,但是毕竟没有本地方便。所以,借助工具(如:Arthas)会更容易分析服务器上的问题。
本文主要参考:https://yq.aliyun.com/articles/645679?utm_content=m_1000017531