您的位置:首页 > 其它

dubbo处理自定义异常问题

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

@ControllerAdvice
@Slf4j
public class ExceptionFilter {

@ExceptionHandler
public ResponseEntity defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {

if(e instanceof MyException){
//自定义处理
}

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


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

下层抛出的异常:

public void text(){
throw new 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 {
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;
}

// 未在方法签名上定义的异常,在服务器端打印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 (exception instanceof RpcException) {
return result;
}

// 否则,包装成RuntimeException抛给客户端
return new 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"/>


d0f7
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  异常 dubbo