其他
谁再悄咪咪的吃掉异常,我上去就是一 JIO
The following article is from 程序通事 Author 楼下小黑哥
1、《往期精选优秀博文都在这里了!》 2、现在的学生太厉害!冒着挂科的风险写的 Spring Cloud 总结 3、Apache Dubbo 被曝出“高危”远程代码执行漏洞 4、Spring Boot自适应异常处理 5、自从用完Gradle后,有点嫌弃Maven了!速度贼快!
Arthas 排查技巧 啥是 NoClassDefFoundError Dubbo 异常内部处理方式
起因
try {
if (!isSupport(req.getChnlCode())) {
return new Response("ERROR", "未找到相关渠道应用");
}
return doPay(req);
} catch (Exception e) {
return new Response("ERROR", "未找到相关渠道应用");
}
}
排查问题
Arthas 排错技巧
Arthas
是Alibaba开源的Java诊断工具,这里就不再详细介绍这个工具,主要讲下这次排错用到的命令-**watch**[2]。返回值
、抛出异常
、入参
,另外还可以通过 OGNL表达式查看对应的变量。doPay
方法,而不是 pay
方法。这是因为 pay
方法中我们将异常捕获,不太可能会抛出异常哦~NoClassDefFoundError
GELogger
相关类。GELogger
类相关源码,从中发现了问题。static {
System.out.println("static init");
logger = Logger.getLogger(NoClassDefFoundErrorTestService.class);
System.out.println("Logger init success");
}
GELogger
存在一个静态代码块,用于初始化一个 org.apache.log4j.Logger
日志类。Log4j
依赖都被排除了,所以这里运行时应该会抛出另外一个找到 org.apache.log4j.Logger
错误。try {
NoClassDefFoundErrorTestService noClassDefFoundErrorTestService=new NoClassDefFoundErrorTestService();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("模拟第二次 Error");
try {
NoClassDefFoundErrorTestService noClassDefFoundErrorTestService=new NoClassDefFoundErrorTestService();
} catch (Throwable e) {
e.printStackTrace();
}
NoClassDefFoundErrorTestService
实例时,Java 虚拟机读取加载时,将会初始化静态代码块时。由于 org.apache.log4j.Logger
类不存在,静态代码块执行异常,从而导致类加载失败。NoClassDefFoundErrorTestService
实例时,Java 虚拟机不会再次读取加载,所以直接返回了以下异常。GELogger
所在依赖包。Dubbo 内部异常处理
GELogger
其实作用在一个 Dubbo 自定义 Filter 中,用来记录结果,模拟代码如下:group = {"provider", "consumer"}
)
public class ErrorFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Result result = invoker.invoke(invocation);
NoClassDefFoundErrorTestService noClassDefFoundErrorTestService=new NoClassDefFoundErrorTestService();
// 处理业务逻辑
return result;
}
}
invoker
方法,这个方法将会调用真正的业务方法,这就是为什么 C2 应用逻辑是正常处理完成。NoClassDefFoundErrorTestService
将会抛出 Error
,最终这个 Error
,将会在 HeaderExchangeHandler#handleRequest
被捕获,然后将会把相关异常信息返回给调用 Dubbo 消费者。DefaultFuture#doReceived
转化成 RemotingException
。RemotingException
最终将会在 FailoverClusterInvoker#doInvoke
转换成 RpcException
返回给业务代码。总结
异常捕获之后,一定要记得打印日志,并且要记得输出堆栈信息。 运行时类不存在,将会导致 NoClassDefFoundError
,类加载过程失败,也会导致NoClassDefFoundError
。对外提供的二方包,最好不要依赖特定日志框架,如 Log4j,Logback 等,应该使用 Slf4j 框架。
参考资料
Arthas: https://alibaba.github.io/arthas/index.html
[2]watch: https://alibaba.github.io/arthas/watch.html
[3]当Dubbo遇上Arthas:排查问题的实践: https://dubbo.apache.org/zh-cn/blog/dubbo-meet-arthas.html
[4]java.lang.NoClassDefFoundError 的解决方法一例: https://www.codelast.com/原创-java-lang-noclassdeffounderror-的解决方法一例/
[5]noclassdeffounderror-could-not-initialize-class-error: https://stackoverflow.com/questions/1401111/noclassdeffounderror-could-not-initialize-class-error
往期热门文章:
3、他来了!IDEA 2020.1 新版介绍!不过升级前请注意避坑!