一、概述

服务发布的过程中,实现类会被ProtocolFilterWrapper进行各种filter的封装,其中就包括ExceptionFilter。那来分析一下ExceptionFilter的代码

二、源码分析

  1. @Activate(group = CommonConstants.PROVIDER)
  2. public class ExceptionFilter extends ListenableFilter {
  3. public ExceptionFilter() {
  4. super.listener = new ExceptionListener();
  5. }
  6. @Override
  7. public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
  8. return invoker.invoke(invocation);
  9. }
  10. static class ExceptionListener implements Listener {
  11. private Logger logger = LoggerFactory.getLogger(ExceptionListener.class);
  12. @Override
  13. public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
  14. if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
  15. try {
  16. //获取方法中抛出的异常。实现方法中的异常在AbstractProxyInvoker中进行反射调用时
  17. //被捕捉封装起来了。这里获取具体的异常信息
  18. Throwable exception = appResponse.getException();
  19. //如果是检查类异常,直接抛出
  20. if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
  21. return;
  22. }
  23. //如果异常是方法签名中声明的异常,则直接抛出
  24. try {
  25. Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
  26. Class<?>[] exceptionClassses = method.getExceptionTypes();
  27. for (Class<?> exceptionClass : exceptionClassses) {
  28. if (exception.getClass().equals(exceptionClass)) {
  29. return;
  30. }
  31. }
  32. } catch (NoSuchMethodException e) {
  33. return;
  34. }
  35. // for the exception not found in method's signature, print ERROR message in server's log.
  36. 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);
  37. //如果异常类和接口类在同一个jar中,则直接抛出该异常
  38. String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
  39. String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
  40. if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {
  41. return;
  42. }
  43. //如果是jdk的异常则直接抛出
  44. String className = exception.getClass().getName();
  45. if (className.startsWith("java.") || className.startsWith("javax.")) {
  46. return;
  47. }
  48. //如果是rpc的异常则直接抛出
  49. if (exception instanceof RpcException) {
  50. return;
  51. }
  52. //否则将异常包装在RuntimeException中,返回给客户端
  53. appResponse.setException(new RuntimeException(StringUtils.toString(exception)));
  54. return;
  55. } catch (Throwable e) {
  56. 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);
  57. return;
  58. }
  59. }
  60. }
  61. @Override
  62. public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
  63. 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);
  64. }
  65. // For test purpose
  66. public void setLogger(Logger logger) {
  67. this.logger = logger;
  68. }
  69. }
  70. }

dubbo异常处理机制设计的初衷:
这个是为了防止服务提供方抛出了消费方没有的异常,比如数据库异常类,导致消费方反序列化失败,使异常信息更奇怪,建议在业务接口上RuntimeException也声明在throws中。