Dubbo 如何处理业务异常,这个一定要知道哦!
provicer 生产者代码

其中的 DataNotFoundException 继承了 BusinessException


DataNotFoundException 的编码以及错误信息:
PUBLIC_DATA_NOT_FOUND(1001,"数据没有找到")
consumer 消费者代码

运行,输入不存在的 goodsID,我们期望我们自定义的异常类被我们拦截到,并做一些处理;但是 provider 生产端抛给消费者的异常竟然是 RuntimeException,只是里面的 message 是我们的业务异常调用栈信息。如下:

不是我们希望的抛给消费者端是 DataNotFoundException 异常。导致我们消费端没法针对不同的业务进行不同的处理。消费端做了 SpringMVC 的异常处理返回了:

上面的 code 为 1401,是系统异常编码,并不是 DataNotFoundException 编码。
我们定义的 DataNotFoundException 的编码为:1001
为什么产生
我们来看看 dubbo 的源码进行分析, 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 如果 Dubbo 的 provider 端 抛出异常(Throwable),则会被 provider 端 的 ExceptionFilter 拦截到,执行以下 invoke 方法,里面有个实现 Listener 类,重写了 onResponse。

我们来分析一些代码:
if (appResponse.hasException() && GenericService.class != invoker.getInterface())
上面代码的含义就是 如果有异常并且未实现 GenericService 接口,进入后续判断逻辑,否则直接返回结果。

上面代码的含义就是 不是 RuntimeException 类型的异常,并且是受检异常(继承 Exception),直接抛出。

上面代码的含义就是 在方法签名上有声明,直接抛出。

上面代码的含义就是 如果异常类和接口类在同一个 jar 包中,直接抛出。

上面代码的含义就是 以 java.或 javax.开头的异常直接抛出。

上面代码的含义就是 dubbo 自身的异常,直接抛出。

不满足上述条件,会做 toString 处理并被封装成 RuntimeException 抛出。
现在我们知道了 **为什么我们自定义的异常,没有正确的抛出,**这个是因为上面的几个条件,我们都没有满足,所以最后 dubbo 把它封装成了 RuntimeException。
如何解决
解决方法就针对上面的几个条件进行,有几种方案,我们一一看一下:
1、将该异常的包名以 java.或者 javax.开头
这个方案不现实,也不符合规范,所以不采用
2、业务异常继承 Exception,变为 checked 异常
自定义的业务异常本身属于 RuntimeException,所以也不采用
3、异常类和接口类在同一 jar 包里
较大的项目一般都会有一些 common 包,定义好异常类型,使用二方包的方式引用,所以也不适用
评论