问题描述

Dubbo有一个比较奇怪的问题,目前不知道Apache和Alibaba公司出于什么样的考虑,貌似一直都没有一个比较合适的解决方案,问题如下:

项目搭建中你需要自定义一个本地的Exception,命名为比如BusinessException。比较一般的书写代码如下:

/**

* @Author linqiang

* @Date 2019/10/24 16:20

* @Version 1.0

* @Description 业务异常类

**/

public class BusinessException extends RuntimeException{

private Integer code;

private String msg;

public BusinessException(Integer code, String msg){

this.code = code;

this.msg = msg;

}

public Integer getCode(){

return code;

}

public String getMsg(){

return msg;

}

}

复制代码

通常这个BusinessException是要能够跨模块使用的,一般放在commons或者core模块中,同时别的模块的pom.xml文件引入这些模块,使得整个项目都可以使用这个BusinessException。

问题来了,如果在A模块调用了B模块,B模块抛出了一个BusinessException,这时A模块接收到的不是BusinessException,而是一个RuntimeException,而且关于BusinessException的细节已经完全丢失,只会剩下一个类名的描述。

问题原因

关于该问题出现的原因,参考这篇文章,归纳一下,就是在Dubbo的传输信息过程中,类ExceptionFilter.java会对Exception做一个过滤,其过滤器的关键代码如下:

// directly throw if it's checked exception

if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {

return;

}

// directly throw if the exception appears in the signature

try {

Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());

Class>[] exceptionClassses = method.getExceptionTypes();

for (Class> exceptionClass : exceptionClassses) {

if (exception.getClass().equals(exceptionClass)) {

return;

}

}

} catch (NoSuchMethodException e) {

return;

}

// for the exception not found in method's signature, print ERROR message in server's log.

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);

// directly throw if exception class and interface class are in the same jar file.

String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());

String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());

if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {

return;

}

// directly throw if it's JDK exception

String className = exception.getClass().getName();

if (className.startsWith("java.") || className.startsWith("javax.")) {

return;

}

// directly throw if it's dubbo exception

if (exception instanceof RpcException) {

return;

}

// otherwise, wrap with RuntimeException and throw back to the client

appResponse.setException(new RuntimeException(StringUtils.toString(exception)));

return;

复制代码

即Dubbo在遇到异常时会这样处理:

非RuntimeException不处理,直接返回

抛出的是方法上注明的异常,直接返回

如果异常类和接口类在同一jar包,直接返回

java或者javax目录下的异常类,直接返回

Dubbo自带的RpcException,直接返回

其他的异常,会被封装为RuntimeException返回

解决方式

根据以上的分析,那么很显然,自定义异常是被直接封装为RuntimeException返回了,而且只带了自定义异常的类名信息,丢失了别的细节。

那么我们想要自定义异常进行正常返回,那只有满足这个FIlter所写的上述条件。我们可以分析一下:

不继承RuntimeException,以检查时异常抛出。不推荐,正常的业务异常应该是运行时异常。

在接口方法上要写上throws BusinessException,如下:

public interface DemoService{

DemoUser getUserInfo(Long userID) throws BusinessException;

}

复制代码

不推荐,不符合接口设计原则,且这样是把运行时异常作为检查时异常处理。

把自定义异常类和接口放在同一个包目录下。不推荐,毕竟这样相当于绑定了异常类的目录,耦合性变高。

改包名,以“java.”或者“javax.”来开头。不推荐,违反了类命名原则。

继承Dubbo的RpcException。RpcException也是继承了RuntimeException,因此能够以RuntimeException的方式进行处理。不推荐,相当于自定义异常属于Dubbo的RpcException,这在程序设计上不合理。

我们发现,想要满足Dubbo的过滤器直接返回异常的条件,我们就必须做出一些违反程序设计的操作,如果一定要从这些方法中选择一种的话,相对来说,自定义异常类和接口放在同一目录下,以及继承RpcException是对于程序侵入性更小的方式。

其他解决方式

参考 这篇文章,提供了两种解决方式:

1.在配置文件中配置如下,效果是:关闭ExceptionFIlter,使所有异常绕过该过滤器直接返回。不推荐,Dubbo既然设置了这个异常过滤类,一定是出于安全和功能上的考虑,直接禁用可能会引发别的问题。

dubbo:

provider:

filter: -exception

复制代码

2.修改Dubbo源文件ExceptionFilter,使其遇到BusinessException也能直接返回。不推荐,相当于定制了本地的Dubbo包,是一个后续很容易被人忽略的大坑。

总结

Dubbo在处理自定义异常时,会直接返回RuntimeException,且抹去自定义异常的所有细节,导致无法处理。

本文写下的时候,Dubbo版本为2.7.3,该问题还没有非常完美的解决方案,相对来说,把自定义异常和接口类放在同一目录下是侵入性最小的方案。

dubbo全局异常处理_详解Dubbo无法处理自定义异常及解决方案相关推荐

  1. java全局异常处理_详解Spring全局异常处理的三种方式

    在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的.不可预知的异常需要处理.每个过程都单独处理异常,系统的代码耦合度高,工作 ...

  2. vue遇到ie兼容问题如何处理_详解vue 兼容IE报错解决方案

    IE 页面空白 报错信息 此时页面一片空白 报错原因 Babel 默认只转换新的 JavaScript 语法(如箭头函数),而不转换新的 API ,比如 Iterator.Generator.Set. ...

  3. dubbo全局异常处理_基于spring aop的dubbo异常统一处理

    dubbo统一异常处理,调用方只显示封装后的异常. 1.返回封装后的Exception 2.返回封装后的统一返回信息 import org.aspectj.lang.annotation.AfterT ...

  4. Dubbo 原理和机制详解

    Dubbo 是一款Java RPC框架,致力于提供高性能的 RPC 远程服务调用方案.作为主流的微服务框架之一,Dubbo 为开发人员带来了非常多的便利. 1. Dubbo核心功能 Dubbo主要提供 ...

  5. Dubbo原理和机制详解(非常全面)

    Dubbo是一款Java RPC框架,致力于提供高性能的RPC远程服务调用方案.Dubbo 作为主流的微服务框架之一,为开发人员带来了非常多的便利. 本文我们重点详解 Dubbo 的原理机制 @mik ...

  6. python gil 解除_详解Python中的GIL(全局解释器锁)详解及解决GIL的几种方案

    先看一道GIL面试题: 描述Python GIL的概念, 以及它对python多线程的影响?编写一个多线程抓取网页的程序,并阐明多线程抓取程序是否可比单线程性能有提升,并解释原因. GIL:又叫全局解 ...

  7. java异常处理机制详解

    java异常处理机制详解 参考文章: (1)java异常处理机制详解 (2)https://www.cnblogs.com/vaejava/articles/6668809.html 备忘一下.

  8. SpringMVC异常处理机制详解[附带源码分析]

    SpringMVC异常处理机制详解[附带源码分析] 参考文章: (1)SpringMVC异常处理机制详解[附带源码分析] (2)https://www.cnblogs.com/fangjian0423 ...

  9. SpringBoot异常处理ErrorController详解

    文章目录 一.背景 二.SpringBoot的默认异常处理BasicErrorController 三.自定义错误异常 写在前面: 我是「境里婆娑」.我还是从前那个少年,没有一丝丝改变,时间只不过是考 ...

最新文章

  1. MySQL 学习笔记(16)— 子查询(单行单列、一行多列、多行多列、 ALL、ANY、SOME 运算符、EXISTS 操作符)
  2. Linux学习 - 目录的权限操作
  3. react antd confirm content list_React造轮系列:对话框组件 - Dialog 思路
  4. electron 前端开发桌面应用
  5. 游戏盒子源码_如何用8K电视盒子组建“家庭影院”(设备入门篇)
  6. js进阶 10-9 -of-type型子元素伪类选择器
  7. Perl线程开发过程中的经验
  8. 【代码源 Div1 - 101】#61. 二分答案(贪心)
  9. 阿里云java面试_20个高级Java面试题汇总
  10. 定时器编写   例子
  11. matlab高等数学实验答案,MATLAB高等数学实验-(第2版)
  12. MATLAB 显示输出数据的三种方式
  13. CF probabilities 自制题单
  14. 感知特性评价指标SSIM
  15. python多级网址爬取_『采集超市』添加多级网址之手动填写链接地址规则
  16. windows10 系统共享文件端口修改
  17. 翻译Guzzle摘要
  18. Glcm 灰度共生矩阵,保姆级别教程,获取图片的Glcm和基于Glcm的纹理特征,附讲解思路,python代码的实现
  19. 一觉醒来,欠费120万,移动程序员要被祭天了!
  20. C#实现在CAD图纸中插入另一个DWG图块的代码

热门文章

  1. redis入门笔记(1)
  2. hibernate dialect 方言 sqlserver2000 的方言
  3. Lync Server 2013企业版部署系列之四:SQL准备
  4. 【Android游戏开发十七】让玩家自定义手势玩转Android游戏!—Android Gesture之【输入法手势技术】...
  5. Windows 网络服务架构系列课程详解(一) ----DHCP服务器的搭建与配置
  6. RMI和WebService
  7. 为什么C语言还是被很多人说成过时了?
  8. 【飞秋怎么用】企业应用
  9. 飞鸽传书:HTML界面也有它欠缺的方面
  10. 用C++访问SQL Server 2000的实例