美文网首页
Dubbo客户端返回自定义异常

Dubbo客户端返回自定义异常

作者: 3c69b7c624d9 | 来源:发表于2017-11-30 22:59 被阅读215次

    虽然上一篇解决了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

    相关文章

      网友评论

          本文标题:Dubbo客户端返回自定义异常

          本文链接:https://www.haomeiwen.com/subject/oxobbxtx.html