背景
在服务化的过程中,基于RPC的服务调用出现异常时,往往需要异常的类进行序列化以及反序列化处理,而在开发的过程中,如果开发人员没有将异常描述类,进行开放处理,经常会出现异常类描述无法得知的问题,所以需要以及全局的补充行为,防止出现异常类不存在,导致异常信息丢失的问题
技术方案
Dubbo的Filter机制,是专门为服务提供方和服务消费方调用过程进行拦截设计的,每次远程方法执行,该拦截都会被执行。这样就为开发者提供了非常方便的扩展性,比如为dubbo接口实现ip白名单功能、监控功能等等。这里将使用fitler作为全局补充异常处理
步骤
自定义FIlter实现方法很简单,分为3个步骤:
1、自定义Filter,必须继承com.alibaba.dubbo.rpc.Filter接口
2、在resources目录下添加纯文本文件META-INF/dubbo/com.alibaba.dubbo.rpc.Filter,内容写成 xxx=xxx.xxx.xxxFilter
3、在dubbo配置xml中添加 <dubbo:provider filter="xxxFilter" /> 或者 <dubbo:consumer filter="xxxFilter" /> 使Filter生效。
代码实现
@Activate(group = Constants.PROVIDER)
public class CommonExceptionFilter implements Filter {
private final Logger logger;
public CommonExceptionFilter() { this(LoggerFactory.getLogger(CommonExceptionFilter.class));
}
public CommonExceptionFilter(Logger logger) {
this.logger = logger;
}
private void fillInStackTrace(Throwable exception) {
exception.setStackTrace(exception.getStackTrace());
}
@Override
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();
//todo ApplicationException 具体的异常类
if (exception instanceof ApplicationException) {//若是业务异常 则直接返回
fillInStackTrace(exception);
return result;
} 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;
}
logger.error("发现未声明的异常类型 " + RpcContext.getContext().getRemoteHost()
+ ". service: " + invoker.getInterface().getName() + ", method: "
+ invocation .getMethodName()
+ ", exception: " + exception.getClass().getName() + ": " + exception
.getMessage(),
exception);
String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
if (serviceFile == null || exceptionFile == null || serviceFile .equals(exceptionFile)) {
return result;
} String className = exception.getClass().getName();
if (className.startsWith("java.") || className.startsWith("javax.")) { return result;
} if (exception instanceof RpcException) {
return result;
} return new RpcResult(new RuntimeException(StringUtils.toString(exception)));
} catch (Throwable e) { logger.warn("执行异常过滤失败 " + 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("发现未声明的异常类型 " + RpcContext.getContext().getRemoteHost()
+ ". service: " + invoker.getInterface().getName() + ", method: " + invocation
.getMethodName()
+ ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
throw e;
} }
}