在进行dubbo调用时,会抛出哪些异常? 为什么有时候是RpcException,有时候又是用户抛出的异常
dubbox2.8.4 中com.alibaba.dubbo.rpc.filter.ExceptionFilter
的注释得知:
1. 如果是checked异常,直接抛出 ! (exception instanceof RuntimeException) && (exception instanceof Exception)
2. 在方法签名上有声明,直接抛出 throws MyCustomException
3. 异常类和接口类在同一jar包里,直接抛出
4. 是JDK自带的异常,直接抛出(className.startsWith("java.") || className.startsWith("javax.")
)
5. 是Dubbo本身的异常,直接抛出(RpcException
)
6. 其他异常通过RpcException
作者都已经贴出代码和注释了. 这还有什么好分析的呢?
这里针对一个场景,对ExceptionFilter类提出一点建议。
provider A 希望服务A,服务B,服务C抛出
MyCustomException
的时候, consumer A 都能获得的是MyCustomException
而不是RpcException
提供者 (provider A) + (provider model) + (common model)
消费者 (consumer A) + (provider model) + (common model)
这样就无法做到 ExceptionFilter 定义的第3条:异常类和接口类在同一jar包里,直接抛出
这时,就得覆盖 ExceptionFilter 相关的代码才可以。
META-INF/dubbo/com.alibaba.dubbo.rpc.Filter
文本文件(文件无后缀), 定义内容ayaDubboExceptionFilter=com.aya.AyaDubboExceptionExtendsFilter
(ayaDubboExceptionFilter必须和Filter配置文件的key一致)说明: ExceptionFilter 的key 是exception
. 要用-exception
删除默认的过滤器
- 自定义的过滤器定义在dubbo:provider>filter属性时, 在 dubbo 内置过滤器之后.
- 未在 dubbo:provider>filter 定义属性时,在 dubbo 内置过滤器之前
// 因为版面原因,省略从ExceptionFilter 抄写的大部分代码
@Activate(group = Constants.PROVIDER)
public class AyaDubboExceptionFilter implements Filter {
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 MyCustomException) {
return result;
}
// 在方法签名上有声明,直接抛出
// 异常类和接口类在同一jar包里,直接抛出
// 是JDK自带的异常,直接抛出
// 是Dubbo本身的异常,直接抛出
// 否则,包装成RuntimeException抛给客户端
return new RpcResult(new RuntimeException(StringUtils.toString(exception)));
} catch (Throwable e) {
return result;
}
}
return result;
} catch (RuntimeException e) {
throw e;
}
}
}
这样就已经替换了原先的ExceptionFilter相关的处理。
但是这样解决的方案真的是太糟糕了. 我居然新建了一个类,把原先的代码抄了一份。
假设原作者能把最后面一句 return new RpcResult(new RuntimeException(StringUtils.toString(exception)));
换成一个可以继承的那就非常好了
public Result invoke(Invoker> invoker, Invocation invocation) throws RpcException {
///省略...
return getDefaultRpcResult(exception);
}
protected RpcResult getDefaultRpcResult(Result result) {
return new RpcResult(new RuntimeException(StringUtils.toString(result.getException())));
}
目前dubbox2.8.4 和 dubbo2.6.1 都存在这样的问题,可以优化
假设原作者按照上述方式修改.我们只要按照下面的方式,就可以自行处理默认的异常了:
protected RpcResult getDefaultRpcResult(Result result) {
if ( result.getException() instanceof MyCustomException) {
return result;
}
return super.getDefaultRpcResult(result);
}