您现在的位置是:主页 > news > 淄博做网站/营销网站建站公司
淄博做网站/营销网站建站公司
admin2025/4/30 11:22:23【news】
简介淄博做网站,营销网站建站公司,注册网站入口,dedecms 5.7 关闭网站今天有小伙伴问小编一个问题,小编觉得还是挺有代表性意义的,有必要拿出来分享下,让读者对dubbo的异常设计有个清晰的认识。问题是这样的:小编的同事作为dubbo服务提供方交付给上游团队一批接口,接口实现中使用到了自定…

今天有小伙伴问小编一个问题,小编觉得还是挺有代表性意义的,有必要拿出来分享下,让读者对dubbo的异常设计有个清晰的认识。
问题是这样的:小编的同事作为dubbo服务提供方交付给上游团队一批接口,接口实现中使用到了自定义异常,我们姑且叫它MyBusinessException吧,当某些特定场景的业务校验失败会将该异常向外抛。但是他在实际的服务消费方发现,无法捕获该MyBusinessException异常信息。这是为什么呢?
要说清楚这个问题,我们要先了解下dubbo rpc远程访问的特点:
- 基于tcp长连接
- 消费方必须持有提供方的接口定义
基于以上特点,实际开发中,服务提供方需要将定义好的api包交付给消费方使用。消费方引用了提供方的api包,那它如何识别提供方的自定义异常呢?正是由于无法保证消费方一定持有提供方定义的自定义异常类,dubbo框架使用ExceptionFilter将服务端异常统一包装成RuntimeException,从而保证了客户端反序列化时不必强制依赖所有的异常类,但随之带来的问题就是会丢失真实异常类信息甚至细节。
我们来看下dubbo对于异常的具体处理过程,在ExceptionFilter注释已经写的非常详细了:
@Activate
重点是这部分:
// 异常类和接口类在同一jar包里,直接抛出 @1String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)){return result;}// 是JDK自带的异常,直接抛出 @2String className = exception.getClass().getName();if (className.startsWith("java.") || className.startsWith("javax.")) {return result;}// 是Dubbo本身的异常,直接抛出 @3if (exception instanceof RpcException) {return result;}// 否则,包装成RuntimeException抛给客户端 @4return new RpcResult(new RuntimeException(StringUtils.toString(exception)));
@1 如果异常类和接口位于同一个api包里,说明消费方已经有这个自定义异常类对象了,返回真是异常信息。
@2 如果是java原生异常,不用说,消费方一定持有异常类对象。
@3 如果异常信息是RpcException,这里不用解释,也不需要再转换了,dubbo框架天生支持。
@4 非以上情况,统一包装成RuntimeException。
读完以上代码,我们就知道了,如果想保留自定义异常信息,一种比较好的做法是将自定义异常打包到api包里,一起交付给消费方使用。但是话有说回来了,实际项目开发过程中的情况很多,可能无法满足这个场景。例如小编的前公司就是将异常信息统一定义在一个公共包里给所有业务团队共用,不允许业务团队自行定义异常。
插个题外话,究竟什么是RPC?RPC(Remote Procedure Call)是远程调用,是一种思想,也是一种协议规范。简单地说就是能使应用像调用本地方法一样的调用远程的过程或服务。RPC的实现方式有很多:如http、webservice、rmi 都算RPC规范范畴。我们今天讨论的dubbo是RPC开源框架,类似的还有:Thrift、gRPC、Motan等等。
总结
dubbo使用ExceptionFilter将服务端异常统一包装成RuntimeException,保证了客户端反序列化时不必依赖所有的异常类,尤其是自定义异常类,但包装会丢失真是异常类信息甚至细节。