1. 程式人生 > >Dubbo丟擲自定義異常時報:Got unchecked and undeclared exception

Dubbo丟擲自定義異常時報:Got unchecked and undeclared exception

轉載: http://blog.csdn.net/xlee1905/article/details/44660449

dubbo的service端定義有自定義異常進行throw的時候,卻發現在Controller中無法instanceof,自己自定義的異常類被轉換成了Runtime異常,dubbo原始碼:

  1. public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {  
  2.     try {  
  3.         Result result = invoker.invoke(invocation);  
  4.         if (result.hasException() && GenericService.class != invoker.getInterface()) {  
  5.             try {  
  6.                 Throwable exception = result.getException();  
  7.                 // 如果是checked異常,直接丟擲
  8.                 if (! (exception instanceof RuntimeException) && (exception 
    instanceof Exception)) {  
  9.                     return result;  
  10.                 }  
  11.                 // 在方法簽名上有宣告,直接丟擲
  12.                 try {  
  13.                     Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());  
  14.                     Class<?>[] exceptionClassses = method.getExceptionTypes();  
  15.                     for (Class<?> exceptionClass : exceptionClassses) {  
  16.                         if (exception.getClass().equals(exceptionClass)) {  
  17.                             return result;  
  18.                         }  
  19.                     }  
  20.                 } catch (NoSuchMethodException e) {  
  21.                     return result;  
  22.                 }  
  23.                 // 未在方法簽名上定義的異常,在伺服器端列印ERROR日誌
  24.                 logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()  
  25.                         + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()  
  26.                         + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);  
  27.                 // 異常類和介面類在同一jar包裡,直接丟擲
  28.                 String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());  
  29.                 String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());  
  30.                 if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)){  
  31.                     return result;  
  32.                 }  
  33.                 // 是JDK自帶的異常,直接丟擲
  34.                 String className = exception.getClass().getName();  
  35.                 if (className.startsWith("java.") || className.startsWith("javax.")) {  
  36.                     return result;  
  37.                 }  
  38.                 // 是Dubbo本身的異常,直接丟擲
  39.                 if (exception instanceof RpcException) {  
  40.                     return result;  
  41.                 }  
  42.                 // 否則,包裝成RuntimeException拋給客戶端
  43.                 returnnew RpcResult(new RuntimeException(StringUtils.toString(exception)));  
  44.             } catch (Throwable e) {  
  45.                 logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost()  
  46.                         + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()  
  47.                         + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);  
  48.                 return result;  
  49.             }  
  50.         }  
  51.         return result;  
  52.     } catch (RuntimeException e) {  
  53.         logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()  
  54.                 + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()  
  55.                 + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);  
  56.         throw e;  
  57.     }  
  58. }  
        所以在dubbo的service端想丟擲自定義異常,只能通過在service端的介面方法上宣告所要丟擲的異常,或者將異常類與介面同包,再或者是介面的實現類再實現dubbo的GenericService介面。

        對於第一種方案沒有使用,因為它對程式碼的入侵比較嚴重。

        第二種方案可以實現,可對於目前的業務框架,讓介面類和異常類同包則變得不太可能。

        所以最後選擇了讓介面實現類再實現GenericService介面,而對於其需要實現的$invoke方法則沒有做任何的方法體處理,直接廢棄。

        對於dubbo的service端自定義異常類的處理,有些不理解的就是,為什麼dubbo需要對自定義異常類做一次Runtime異常的轉化,而不是直接丟擲原異常型別。或者有沒有對dubbo更瞭解的朋友,有對自定義異常更好的處理方法。