Dubbo如何處理業務異常,這個一定要知道哦

前言

我們在開發應用系統時,不可避免的要使用到我們自己定義的異常,所以我們一般通常會用到自定義的業務異常類BusinessException,這個異常會繼承extends RuntimeException,當發生業務限制的時候,會throw出來。

問題

在SpringMVC項目中,我們可以採用@ControllerAdvice註解,攔截我們的業務異常類,然後做一些處理。

網上有很多SpringMVC項目如何統一處理異常。老顧這裡就不做介紹

但是現在項目都是微服務化的,在使用dubbo構建項目時,會發現provider拋出自定義業務異常,在custom端並不能正確的捕獲。即便我們在provider和custom都有導入相同jar包下面的BusinessException異常,並且拋出這個異常。下面是出錯情況

老顧採用dubbo版本為2.7.3版本,跟老版本有點區別,但區別不大

provicer生產者代碼

Dubbo如何處理業務異常,這個一定要知道哦

其中的DataNotFoundException繼承了BusinessException

Dubbo如何處理業務異常,這個一定要知道哦

Dubbo如何處理業務異常,這個一定要知道哦

<code>
DataNotFoundException 的編碼以及錯誤信息:

PUBLIC_DATA_NOT_FOUND(1001,"數據沒有找到")

/<code>

consumer消費者代碼

Dubbo如何處理業務異常,這個一定要知道哦

運行,輸入不存在的goodsID,我們期望我們自定義的異常類被我們攔截,並做一些處理;但是provider生產端拋給消費者的異常竟然是RuntimeException,只是裡面的message是我們的業務異常調用棧信息。如下:

Dubbo如何處理業務異常,這個一定要知道哦

不是我們希望的拋給消費者端是DataNotFoundException異常。導致我們消費端沒法針對不同的業務進行不同的處理。消費端做了SpringMVC的異常處理返回了:

Dubbo如何處理業務異常,這個一定要知道哦

上面的code為1401,是系統異常編碼,並不是DataNotFoundException編碼。

我們定義的DataNotFoundException的編碼為:1001

為什麼產生

我們來看看dubbo的源碼進行分析,如果Dubbo的 provider端 拋出異常(Throwable),則會被 provider端 的ExceptionFilter攔截到,執行以下invoke方法,

裡面有個實現Listener類,重寫了onResponse。

Dubbo如何處理業務異常,這個一定要知道哦

我們來分析一些代碼:

<code>
if (appResponse.hasException() && GenericService.class != invoker.getInterface())

/<code>

上面代碼的含義就是 如果有異常並且未實現GenericService接口,進入後續判斷邏輯,否則直接返回結果。

Dubbo如何處理業務異常,這個一定要知道哦

上面代碼的含義就是 不是RuntimeException類型的異常,並且是受檢異常(繼承Exception),直接拋出。

Dubbo如何處理業務異常,這個一定要知道哦

上面代碼的含義就是 在方法簽名上有聲明,直接拋出。

Dubbo如何處理業務異常,這個一定要知道哦


上面代碼的含義就是 如果異常類和接口類在同一個jar包中,直接拋出。

Dubbo如何處理業務異常,這個一定要知道哦


上面代碼的含義就是 以java.或javax.開頭的異常直接拋出。

Dubbo如何處理業務異常,這個一定要知道哦


上面代碼的含義就是dubbo自身的異常,直接拋出。

Dubbo如何處理業務異常,這個一定要知道哦


不滿足上述條件,會做toString處理並被封裝成RuntimeException拋出。

現在我們知道了 為什麼我們自定義的異常,沒有正確的拋出,這個是因為上面的幾個條件,我們都沒有滿足,所以最後dubbo把它封裝成了RuntimeException。

如何解決

解決方法就針對上面的幾個條件進行,有幾種方案,我們一一看一下:

1、將該異常的包名以java.或者javax.開頭

這個方案不現實,也不符合規範,所以不採用

2、業務異常繼承Exception,變為checked異常

自定義的業務異常本身屬於RuntimeException,所以也不採用

3、異常類和接口類在同一jar包裡

較大的項目一般都會有一些common包,定義好異常類型,使用二方包的方式引用,所以也不適用

4、provider的api明確寫明throws XxxException

作為生產服務端,不應顯式拋出異常給客戶的進行處理,所以也不適用

最終方案

以上方案都不合適,我們這裡介紹個最終的方案,即採用dubbo的filter重寫,dubbo的異常處理。

1、將dubbo源碼中ExceptionFilter複製到我們的項目改名為DubboExceptionFilter修改一些代碼

Dubbo如何處理業務異常,這個一定要知道哦

2、在此處加上一段代碼來過濾我們項目中的異常,以免被dubbo重新封裝3、在resources目錄下添加純文本文件META-INF/dubbo/com.alibaba.dubbo.rpc.Filter並添加內容

Dubbo如何處理業務異常,這個一定要知道哦

<code>
dubboExceptionFilter=com.rainbow.goods.server.filter.
DubboExceptionFilter

/<code>

4、

修改dubbo 的配置文件,將DubboExceptionFilter加載進去並且去掉自身的ExceptionFilter

<code>
<providerfilter>

/<code>

上面exception就是dubbo默認的處理異常的filter,前面-號就代表去除

我們修改後,再運行:

Dubbo如何處理業務異常,這個一定要知道哦

拋出的是我們自定義的異常了,在看看消費端的異常處理最終顯示


Dubbo如何處理業務異常,這個一定要知道哦

確實是我們定義的DataNotFoundException業務異常的編碼和信息。

總結

上面的是基於重寫dubbo的filter處理了異常,網上有一些別的方案,老顧認為不是太合理,不夠靈活,利用修改dubbo源碼的方式解決更能徹底解決;

希望能夠給小夥伴帶來幫助。謝謝!!!

Dubbo如何處理業務異常,這個一定要知道哦


分享到:


相關文章: