dubbo的Exception堆栈 丢失 处理
研究背景
希望dubbo
服务端抛出的异常完整的传递给客户端,最终到达最高层,统一进行异常的处理和堆栈的记录。
不使用ExceptionFilter
会出现java原生的异常堆栈消失,没有空参构造器的自定义异常堆栈能够在服务端出现,而有空参构造器的自定义异常堆栈也消失的情况。
问题分析
public Serializer getDefaultSerializer(Class type) {
if (type == null) {
throw new IllegalArgumentException("type cannot be null.");
}
if (!type.isArray() && !ReflectionUtils.checkZeroArgConstructor(type)) {
if (logger.isWarnEnabled()) {
logger.warn(type + " has no zero-arg constructor and this will affect the serialization performance");
}
return new JavaSerializer();
}
return super.getDefaultSerializer(type);
}
发现,原来是dubbox优化之后造成的结果,当需要被序列化的对象没有空参构造器时,dubbox会放弃使用Kryo
而使用java
序列化方案。很可能就是这个优化方案导致上述怪异情况的发生。
默认的ExceptionFilter
关键代码:
2016-06-07 14:19:26.096 ERROR 14278 --- [nio-8081-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ArrayIndexOutOfBoundsException: 异常] with root cause
java.lang.ArrayIndexOutOfBoundsException: 异常
而对于最后不符合条件的异常,会使用dubbo
的toString()
方法将异常转化为String
,然后再包一层RuntimeException
往外抛出,那么理论上我们将会看到一个detailMessage
类似堆栈,但没有堆栈的一段信息。如下所示:
// 否则,包装成RuntimeException抛给客户端
return new RpcResult(new RuntimeException(StringUtils.toString(exception)));
这个乍看只是toString()
,可谁知道他在里面干了什么。我们就来看一下这个toString()
方法:
try {
throw new ArrayIndexOutOfBoundsException("异常");
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace()
throw e
}
这个时候,客户端就能够完整的记录下异常的堆栈。联想到dubbo
的toString()
方法里面也有printStackTrace()
这个方法,所以他也打出了堆栈。难道printStackTrace()
方法不为人知的还做了一些除了打印之外的事情?
来看下printStackTrace()
最终调用的代码:
StackTraceElement[] trace = getOurStackTrace();
通过私有方法getOurStackTrace()
获取了异常的堆栈:
private void fillInStackTrace(Throwable exception) {
exception.setStackTrace(exception.getStackTrace());
}
稍微修改一下原来的invoke()
逻辑,在获取到exception
之后,预处理一下。
解决和不足
启用自定义的ExceptionFilter
,发现问题完美解决。唯一不足之处是,由于我们对于堆栈的处理并没有处理成String
,那么在异常传回客户端反序列化时,如果堆栈中包含的某些类在客户端中不存在时,会出现反序列化失败的情况,所以一定要保证所有的异常(主要是自定义异常)被客户端也依赖了。
作者:钱嘉鑫
链接:https://www.jianshu.com/p/dc9a180cca61
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。