dubbo处理自定义异常问题

2022-06-23 10:08:24

最近在项目上遇到一个有关dubbo的问题,项目分为两层:下层是一些基础服务,上层是业务服务调用下层的基础服务。上层服务的有一个全局的异常拦截器来拦截异常。

@ControllerAdvice@Slf4jpublicclassExceptionFilter {@ExceptionHandlerpublic ResponseEntitydefaultErrorHandler(HttpServletRequest req, Exception e)throws Exception {if(einstanceof MyException){//自定义处理
        }

        log.error(e.getMessage(), e);
        Result res =new Result(500,"SYSTEM_EXCEPTIONS","系统异常");return ResponseEntity.ok(res);
    }
}

全局异常可以catch程序上层的异常,进行不同的处理,进行更加友好的提示。
下层抛出的异常:

publicvoidtext(){thrownew MyException("aaaa");
}

然后遇到了一个奇怪的问题,在下层中抛出了一个自定义的异常,但是在上层中捕获异常的时候,却是捕获到runtimeException异常,异常中的message存放了我们需要的对象异常。导致就无法对自定义的异常做特殊处理。

java.lang.RuntimeException:MyException: aaa

查阅了一下资料以后是因为dubbo对异常进行了处理,如果Dubbo的暴露抛出异常(Throwable),则会被暴露方的ExceptionFilter拦截到,执行以下invoke方法:

public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {try {
            Result result = invoker.invoke(invocation);if (result.hasException() && GenericService.class != invoker.getInterface()) {try {
                    Throwableexception = result.getException();// 如果是checked异常,直接抛出if (! (exceptioninstanceof RuntimeException) && (exceptioninstanceofException)) {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;
                    }// 未在方法签名上定义的异常,在服务器端打印ERROR日志
                    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);// 异常类和接口类在同一jar包里,直接抛出
                    String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
                    String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());if (serviceFile ==null || exceptionFile ==null || serviceFile.equals(exceptionFile)){return result;
                    }// 是JDK自带的异常,直接抛出
                    String className =exception.getClass().getName();if (className.startsWith("java.") || className.startsWith("javax.")) {return result;
                    }// 是Dubbo本身的异常,直接抛出if (exceptioninstanceof RpcException) {return result;
                    }// 否则,包装成RuntimeException抛给客户端returnnew RpcResult(new RuntimeException(StringUtils.toString(exception)));
                }catch (Throwable e) {
                    logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost()
                            +". service: " + invoker.getInterface().getName() +", method: " + invocation.getMethodName()
                            +", exception: " + e.getClass().getName() +": " + e.getMessage(), e);return result;
                }
            }return result;
        }catch (RuntimeException e) {
            logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()
                    +". service: " + invoker.getInterface().getName() +", method: " + invocation.getMethodName()
                    +", exception: " + e.getClass().getName() +": " + e.getMessage(), e);throw e;
        }
    }

从代码可以看出,duubo只会抛出受检异常、jdk自身的异常、方法上申明的异常、dubbo自带的RpcException异常等等,其他的都会包装成new RuntimeException(StringUtils.toString(exception))抛出,所以也有了我遇到的问题。

只要的发生问题的原因就可以解决问题:

  • 可以在暴露方法的时候声明异常
  • 可以把异常设置为受检异常
  • 可以把异常和api包放在同一个jar包中
  • provider实现GenericService接口
  • 自定义异常继承dubbo的异常类

上述方法是在ExceptionFilter的基础上,可以换个思路,通过订制错误码,把遗产放在对象中进行处理,不过这个思路对使用方的改动较大,需要在开始定义架构的时候的时候进行约定。也可以使用修改配置文件跳过ExceptionFilter这个拦截器,但是这样做暴露方会把所有的原始异常暴露给使用者。

跳过异常拦截器的配置

    <dubbo:provider .......... filter="-exception"/>
  • 作者:lkj41110
  • 原文链接:https://blog.csdn.net/qq_25673113/article/details/78574514
    更新时间:2022-06-23 10:08:24