一、概述
服务发布的过程中,实现类会被ProtocolFilterWrapper进行各种filter的封装,其中就包括ExceptionFilter。那来分析一下ExceptionFilter的代码
二、源码分析
@Activate(group = CommonConstants.PROVIDER)
public class ExceptionFilter extends ListenableFilter {
public ExceptionFilter() {
super.listener = new ExceptionListener();
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
return invoker.invoke(invocation);
}
static class ExceptionListener implements Listener {
private Logger logger = LoggerFactory.getLogger(ExceptionListener.class);
@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
try {
//获取方法中抛出的异常。实现方法中的异常在AbstractProxyInvoker中进行反射调用时
//被捕捉封装起来了。这里获取具体的异常信息
Throwable exception = appResponse.getException();
//如果是检查类异常,直接抛出
if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
return;
}
//如果异常是方法签名中声明的异常,则直接抛出
try {
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
Class<?>[] exceptionClassses = method.getExceptionTypes();
for (Class<?> exceptionClass : exceptionClassses) {
if (exception.getClass().equals(exceptionClass)) {
return;
}
}
} catch (NoSuchMethodException e) {
return;
}
// for the exception not found in method's signature, print ERROR message in server's log.
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;
}
//如果是jdk的异常则直接抛出
String className = exception.getClass().getName();
if (className.startsWith("java.") || className.startsWith("javax.")) {
return;
}
//如果是rpc的异常则直接抛出
if (exception instanceof RpcException) {
return;
}
//否则将异常包装在RuntimeException中,返回给客户端
appResponse.setException(new RuntimeException(StringUtils.toString(exception)));
return;
} 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;
}
}
}
@Override
public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
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);
}
// For test purpose
public void setLogger(Logger logger) {
this.logger = logger;
}
}
}
dubbo异常处理机制设计的初衷:
这个是为了防止服务提供方抛出了消费方没有的异常,比如数据库异常类,导致消费方反序列化失败,使异常信息更奇怪,建议在业务接口上RuntimeException也声明在throws中。