1. 程式人生 > >dubbo自定義異常傳遞資訊丟失問題解決

dubbo自定義異常傳遞資訊丟失問題解決

訪問我的部落格

目前計劃對已有的單體專案進行組織架構拆分,調研了分散式系統中常用中介軟體 Dubbo 和 Spring Cloud,選擇了 Dubbo,可以對當前現有專案進行平滑升級改造。但是一開始就遇到了麻煩,自定義異常在傳遞的過程中變成了 RuntimeException,統一異常處理 GlobalExceptionHandler 無法獲取異常資訊。

問題重現

專案進行統一異常處理,抽取了一個通用異常 ServiceException,此異常是非受檢異常,即繼承於 RuntimeException。調研時發現如果服務提供方即 provider 丟擲了 ServiceException

異常,consumer 服務消費方就會收到一個 RuntimeException 異常,而 ServiceException 異常的內容被包含在了 RuntimeException 的異常堆疊中

[Request processing failed; nested exception is java.lang.RuntimeException: io.github.mosiki.common.exception.ServiceException: missing_required_parameters
io.github.mosiki.common.exception.ServiceException: missing_required_parameters
    at io.github.mosiki.provider.HelloService.sayHello(HelloService.java:20)
    at com.alibaba.dubbo.common.bytecode.Wrapper1.invokeMethod(Wrapper1.java)

而我的統一異常處理是這樣的,只處理 ServiceException 以及 Exception,因此就無法獲取到原始異常的資訊了。

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ServiceException.class)
    public Result handlerServiceException(ServiceException ex) {
        return Result.failure(ex.getCode(), ex.getMessage());
    }

    @ExceptionHandler({Exception.class})
    public Result handlerException(Exception ex) {
        log.error("發生未知異常:{}", ex);
        return Result.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), "伺服器打了個小盹兒~請稍候再試");
    }
}

訪問介面將返回如下,異常中原有資訊丟失。

上網搜尋發現,這是因為 dubbo 的異常處理類 com.alibaba.dubbo.rpc.filter.ExceptionFilter 進行處理後的結果,Debug 之後確實如此,dubbo 在此進行了轉換。

問題解決之道

現在我想要 provider 把自定義的異常原封不動的拋給 consumer 進行處理,於是有了如下思路:

  1. 禁用 provider 的 ExceptionFilter
  2. 讓 GlobalExceptionHandler 處理 consumer 的異常

按照此思路做就很簡單了,網上大多文章的辦法都比較麻煩,有用 AOP 處理的,甚至還有讓自己修改編譯原始碼上傳私服的-_-||,本文給出比較簡便的方法,提供參考。

禁用provider的ExceptionFilter

修改 provider 的配置,我這裡使用 yml 配置檔案,其他型別如 xml/properties 也同理,設定 provider 的 filter 為 -exception,這樣異常就不會被處理而是直接丟擲了。

dubbo:
  application:
    name: provider
  protocol:
    name: dubbo
    port: 20100
  registry:
    address: 127.0.0.1:2181
    protocol: zookeeper
  provider:
    filter: -exception

GlobalExceptionHandler捕獲ServiceException

只是禁用了 provider 的 ExceptionHandler 還不能完全達到我們的目的,訪問介面,provider 丟擲異常 consumer 正確接收為 ServiceException

[Request processing failed; nested exception is io.github.mosiki.common.exception.ServiceException: missing_required_parameters] with root cause

io.github.mosiki.common.exception.ServiceException: missing_required_parameters
    at io.github.mosiki.provider.HelloService.sayHello(HelloService.java:20) ~[na:na]
    at com.alibaba.dubbo.common.bytecode.Wrapper1.invokeMethod(Wrapper1.java) ~[na:na]

我們處理一下 GlobalExceptionHandler。

SpringBoot 主要這個啟動類的位置和全域性異常處理器的位置,一定要保證異常處理器在啟動類的同級包或者在啟動類的子包當中,否則異常處理器將不生效!

效果展示

以上兩步完成後,重啟服務,訪問介面測試。

拿到了 provider 丟擲的原始自定義異常,如此問題就解決了。

程式碼下載

參考

  • https://blog.csdn.net/yangzaizi/article/details/80638306