深入Spring Boot:利用Arthas排查NoSuchMethodError

前言

有时spring boot应用会遇到java.lang.NoSuchMethodError的问题,下面以具体的demo来说明怎样利用arthas来排查。

Demo: https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-NoSuchMethodError

在应用的main函数里catch住异常,保证进程不退出

很多时候当应用抛出异常后,进程退出了,就比较难排查问题。可以先改下main函数,把异常catch住:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) throws IOException {
try {
SpringApplication.run(DemoNoSuchMethodErrorApplication.class, args);
} catch (Throwable e) {
e.printStackTrace();
}
// block
System.in.read();
}

Demo启动之后,抛出的异常是:

1
2
3
4
5
6
7
8
java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationAwareOrderComparator.sort(Ljava/util/List;)V
at 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这个函数。

安装arthas

参考:https://alibaba.github.io/arthas/install-detail.html

使用sc命令查找类所在的jar包

应用需要抛出了异常,但是进程还没有退出,我们用arthas来attach上去。比如在mac下面:

1
./as.sh

然后选择com.example.demoNoSuchMethodError.DemoNoSuchMethodErrorApplication进程。

再执行sc命令来查找类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ sc -d org.springframework.core.annotation.AnnotationAwareOrderComparator
class-info org.springframework.core.annotation.AnnotationAwareOrderComparator
code-source /Users/hengyunabc/.m2/repository/org/springframework/spring/2.5.6.SEC03/spring-2.5.6.SEC03.jar
name org.springframework.core.annotation.AnnotationAwareOrderComparator
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name AnnotationAwareOrderComparator
modifier public
annotation
interfaces
super-class +-org.springframework.core.OrderComparator
+-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@5c647e05
+-sun.misc.Launcher$ExtClassLoader@689e3d07
classLoaderHash 5c647e05

Affect(row-cnt:1) cost in 41 ms.

可以看到AnnotationAwareOrderComparator是从spring-2.5.6.SEC03.jar里加载的。

使用jad查看反编绎的源代码

下面使用jad命令来查看AnnotationAwareOrderComparator的源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ jad org.springframework.core.annotation.AnnotationAwareOrderComparator

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@5c647e05
+-sun.misc.Launcher$ExtClassLoader@689e3d07

Location:
/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函数。

排掉依赖,解决问题

从上面的排查里,可以确定

  • AnnotationAwareOrderComparator来自spring-2.5.6.SEC03.jar,的确没有sort(Ljava/util/List;)V函数。

所以,可以检查maven依赖,把spring 2的jar包排掉,这样子就可以解决问题了。

总结

  • 仔细看NoSuchMethodError的异常信息,了解是什么类缺少了什么函数
  • 利用arthas来查找类,反编绎源码,确认问题

链接

横云断岭/hengyunabc wechat
欢迎您扫一扫上面的微信公众号,订阅横云断岭的专栏