Dubbo异常处理


声明:本文转载自https://my.oschina.net/qixiaobo025/blog/1142720,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

小伙伴在使用dubbo过程中推出了疑问,部分自定义异常不见了,变成了RuntimeException。并且message超长。

如下图

我们来查看一下Dubbo中如何对待自定义异常的。来到ExceptionFilter

/**  * ExceptionInvokerFilter  * <p>  * 功能:  * <ol>  * <li>不期望的异常打ERROR日志(Provider端)<br>  *     不期望的日志即是,没有的接口上声明的Unchecked异常。  * <li>异常不在API包中,则Wrap一层RuntimeException。<br>  *     RPC对于第一层异常会直接序列化传输(Cause异常会String化),避免异常在Client出不能反序列化问题。  * </ol>  *  * @author william.liangf  * @author ding.lid  */ @Activate(group = Constants.PROVIDER) public class ExceptionFilter implements Filter {       private final Logger logger;           public ExceptionFilter() {         this(LoggerFactory.getLogger(ExceptionFilter.class));     }           public ExceptionFilter(Logger logger) {         this.logger = logger;     }           public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {         try {             Result result = invoker.invoke(invocation);             if (result.hasException() && GenericService.class != invoker.getInterface()) {                 try {                     Throwable exception = result.getException();                       // 如果是checked异常,直接抛出                     if (! (exception instanceof RuntimeException) && (exception instanceof Exception)) {                         return result;                     }                     // 在方法签名上有声明,直接抛出                     try {                         Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());                         Class<?>[] exceptionClassses = method.getExceptionTypes();                         for (Class<?> exceptionClass : exceptionClassses) {                             if (exception.getClass().equals(exceptionClass)) {                                 return result;                             }                         }                     } catch (NoSuchMethodException e) {                         return result;                     }                       // 未在方法签名上定义的异常,在服务器端打印ERROR日志                     logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()                             + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()                             + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);                       // 异常类和接口类在同一jar包里,直接抛出                     String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());                     String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());                     if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)){                         return result;                     }                     // 是JDK自带的异常,直接抛出                     String className = exception.getClass().getName();                     if (className.startsWith("java.") || className.startsWith("javax.")) {                         return result;                     }                     // 是Dubbo本身的异常,直接抛出                     if (exception instanceof RpcException) {                         return result;                     }                       // 否则,包装成RuntimeException抛给客户端                     return new RpcResult(new RuntimeException(StringUtils.toString(exception)));                 } catch (Throwable e) {                     logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost()                             + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()                             + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);                     return result;                 }             }             return result;         } catch (RuntimeException e) {             logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()                     + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()                     + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);             throw e;         }     }   }
  1. 如果是受检异常直接抛出(当然可以,因为必须在签名中声明,如果客户端不引用异常包直接编译报错)
  2. 如果方法签名上引用,直接抛出(和1一样的原因)
  3. 判断接口api和抛出的exception是否在一个jar,是直接抛出
  4. 如果是jdk的异常直接抛出(其实部分jar不遵守该约定,使用了java或者javax的包,可能出错哦,客户端端无法反序列化)
  5. 如果是Dubbo本身的异常直接抛出(此处代码乍看有问题,instanceof RpcException 不能表示一定是Dubbo自定义的,因为可以继承。可是深入查看该异常为final,不可以继承。)
  6. 否则将异常转换为RuntimeException

因此出现了如上图的结果。导致在系统中可能出现异常转化为RuntimeException,并且会将堆栈信息一起写入message,导致message超长。(可以通过复写异常类的fillStackTrace来解决过长的问题)

对于自定义异常可能可以做到将异常和接口包装在同一个jar。但是部分依赖外部异常可能无法做到。

解决方案 

  1. 在异常返回到消费者之前提前包装成自定义异常(自定义异常和接口打在同一个jar中)
  2. 显示声明异常在方法签名

本文发表于2017年07月03日 18:36
(c)注:本文转载自https://my.oschina.net/qixiaobo025/blog/1142720,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2197 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1