文档章节

Dubbo客户端返回自定义异常

Mr_Qi
 Mr_Qi
发布于 2017/07/04 18:13
字数 614
阅读 814
收藏 2

虽然上一篇解决了message过长的问题 Dubbo自定义异常message过长解决

但是小伙伴仍然反映对于异常不能使用原类型而导致邮件报错太多(邮件报错基于错误类型来的,比如定义的某种参数异常不需要要发邮件)

而基于上文的分析代码中不支持返回是添加Attachment。

那么只能通过其他途径了。

/**
 * Created by qixiaobo on 2017/7/3.
 */
@Activate(group = Constants.PROVIDER, before = {"exception"}, value = {"customException"})
public class CustomExceptionFilter implements Filter {
    private static Logger logger = LoggerFactory.getLogger(CustomExceptionFilter.class);
 
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        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;
                }
                // 是JDK自带的异常,直接抛出
                String className = exception.getClass().getName();
                if (className.startsWith("java.") || className.startsWith("javax.")) {
                    return result;
                }
                // 是Dubbo本身的异常,直接抛出
                if (exception instanceof RpcException) {
                    return result;
                }
                //其他exception ,减少问题,直接将exception序列化成RuntimeException,同时放入指定的异常类型值attachment中
                // 否则,包装成RuntimeException抛给客户端
                result = new RpcResult(new RuntimeException(exception.getClass().getName()+"#"+exception.getMessage()));
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
                return result;
            }
        }
        return result;
    }
}

和上文相比将异常类型藏在了Exception的message中

@Activate(group = Constants.CONSUMER, value = {"clientException"})
public class ClientExceptionFilter implements Filter {
    private static Logger logger = LoggerFactory.getLogger(ClientExceptionFilter.class);
 
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Result result = invoker.invoke(invocation);
        if (result.hasException()) {
            Throwable exception = result.getException();
            if ((exception instanceof RuntimeException)) {
                //可能是自定义异常
                String message = exception.getMessage();
                if (exception.getMessage() != null) {
                    String[] messages = message.split("#", 2);
                    if (messages.length == 2) {
                        try {
                            logger.debug("message:{}", message);
                            Class exceptionClass = Class.forName(messages[0]);
                            try {
                                Constructor messageConstructor = exceptionClass.getConstructor(String.class);
                                messageConstructor.setAccessible(true);
                                exception = (Throwable) messageConstructor.newInstance(messages[1]);
                            } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
                                try {
                                    logger.debug(e.getMessage(), e);
                                    Constructor constructor = exceptionClass.getConstructor();
                                    constructor.setAccessible(true);
                                    exception = (Throwable) constructor.newInstance();
                                } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e1) {
                                    logger.debug(e1.getMessage(), e1);
                                }
                            }
                            if (result instanceof RpcResult) {
                                ((RpcResult) result).setException(exception);
                            }
                        } catch (ClassNotFoundException e) {
                            logger.warn(e.getMessage(), e);
                        }
                    }
 
                }
            }
        }
        return result;
    }
}

自定义客户端的filter,当应用该filter时

  1. 只校验RuntimeException(上文中异常均背转化为RuntimeException)
  2. 拆分RuntimeException
  3. 将类型取出后直接转化为异常类,调用器构造函数(优先尝试message,其次尝试默认构造函数)
  4. 将异常重新塞回RpcResult

在客户端的dubbo声明中如下

<dubbo:consumer timeout="60000" group="${dubbo.group}" retries="0" owner="qixiaobo" id="f6-consumer" filter="clientException"/>

在抛弃堆栈信息后序列化数据变少,并且客户端无感知

要求该异常在客户端必须存在,否则仍然是RuntimeException

© 著作权归作者所有

共有 人打赏支持
Mr_Qi

Mr_Qi

粉丝 280
博文 359
码字总数 369228
作品 0
南京
程序员
私信 提问
使用Dubbo中需要注意的事项

一、前言 Dubbo作为高性能RPC框架,已经进入Apache卵化器项目,虽然官方给出了dubbo使用的用户手册,但是大多是一概而过,使用dubbo时候要尽量了解源码,不然会很容易入坑。 二 、服务消费端...

加多
2018/01/02
0
0
dubbo超时异常

dubbo超时异常 在调用dubbo服务时经常看到如下错误:Caused by: com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. 源码分析 客户端调用远......

lipengHeke
2018/02/05
13
0
Dubbo使用Sentinel来对服务进行降级与限流

一、Sentinel 是什么 Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的...

nonnetta
2018/12/24
0
0
dubbo学习过程、使用经验分享及实现原理简单介绍,dubbo经验分享

一、前言 整理这篇文章差不多花了两天半时间,请尊重劳动成果,如转载请注明出处http://blog.csdn.net/hzzhoushaoyu/article/details/43273099 二、什么是dubbo Dubbo是阿里巴巴提供的开源的...

沉默的子明
2016/06/23
647
0
Dubbo 同步、异步调用的几种方式

我们知道,Dubbo 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制;基于这种机制,Dubbo 实现了以下几种调用方式: 同步调用 异步调用 参数回调 事件通知 同步调用 同步调用是...

meiqinqin
2018/07/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

看过上百部片子的这个人教你视频标签算法解析

本文由云+社区发表 随着内容时代的来临,多媒体信息,特别是视频信息的分析和理解需求,如图像分类、图像打标签、视频处理等等,变得越发迫切。目前图像分类已经发展了多年,在一定条件下已经...

腾讯云加社区
13分钟前
0
0
2. 红黑树

定义:红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树(Binary Search Tree)。 要理解红黑树,先要了解什么是二叉查找树。在上一章中,我们学习了什么是二叉树,以及二叉树...

火拳-艾斯
14分钟前
0
0
input的button类型,点击页面跳转

一、input type=button 不做任何操作 例如: <input type="button" class="btn btn-primary" style="width: 30%" value="返回" onclick="window.location.href='/users/list'"></input> onc......

Sunki
20分钟前
0
0
踩坑:js 小数运算出现精度问题

背景 在学习小程序商城源码时发现了这个问题,单价可能出现小数,小数之间运算结果会莫名其妙多出一大串数字,比如下面这样👇。 在此之前我是知道 js 中著名的 0.1 + 0.2 != 0.3 的问题的,...

dkvirus
26分钟前
0
0
zookeeper和HBASE总结

zookeeper快速上手 zookeeper的基本功能和应用场景 zookeeper的整体运行机制 zookeeper的数据存储机制 数据存储形式 zookeeper中对用户的数据采用kv形式存储 只是zk有点特别: key:是以路径...

瑞查德-Jack
49分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部