本文討論的前提是在捕獲了異常的情況下進行的說明。
1、 直接使用原生異常。直接拋出 Exception 或者 RuntimeException。
在業務代碼層,直接拋出異常信息。這里不限定RuntimeException還是其他。
好處是,簡單方便直接。
壞處是,部分調用方需要顯式的拋出異常,且提示語不方便管理。
2、 項目包裝RuntimeException。
直接繼承RuntimeException,做一些簡單的封裝,類似如下代碼
開發同學在使用時,直接new一個即可。總共兩個構造方法可選,或者直接使用靜態方法,生成包含對應detail的異常信息。其中常用的錯誤碼、錯誤信息,都用一個靜態類或者是枚舉保存。我猜測大部分信息都采用的這種方式,而且這樣的方式也滿足一般的管理系統。
好處是方便,有一定的標准。
壞處是多個模塊的開發者維護同一個枚舉容易出現沖突,容易出現一個錯誤碼被多次使用。
3、 多語言。
如果公司業務發展較快,明天要進軍泰國市場,后天要進軍沙特阿拉伯市場,那就得在枚舉全部新增一套提示語。雖然這樣的改動不難,但沒啥技術含量。
所以我們將保存錯誤信息的枚舉類進行改造,如下圖
重寫toString方法
這樣就會帶來問題,因為每次都需要新增加或者維護異常信息,都需要維護枚舉類現有的幾套語言。
好處是方便,比較容易管理,支持多語言。
壞處當然是浪費開發的時間,且一旦出現提示語不對,還需要重新發版,費時費力。
4、 可配置的異常提示信息。
那既然現在的痛點是在維護上,我們何不考慮做成可配置?
以將異常信息放在數據為例,先看兩張表。
此時,發生異常,若代碼拋出異常,必須帶上exception_code,異常處理service去包裝異常信息,一方面返回異常信息給用戶,一方面將異常信息入庫。
以springboot 為例
異常信息的包裝策略此處不展開,各位可以自己想想如何包裝。
這里好處就是異常信息可以隨時調整,十分靈活,開發進行排查時也能有的放矢,不用去整個日志系統一遍一遍的去搜。
壞處可能就是寫的代碼有點多,搞這么復雜一時半會也沒啥用。
5、 分布式系統的異常信息傳遞。
這里會與全鏈路日志追蹤有交叉的地方。
舉個栗子,我在手機qq查看聯系人性別:
a) 打開手機qq(開始讀取消息)
b) 打開聯系人列表(讀取在線狀態)
c) 讀取各種群消息(未收到的群消息)
d) 搜索聯系人(本地搜索+服務器搜索)
e) 點開聯系人詳情頁(獲取用戶通用基本信息、用戶允許查看的隱私信息、用戶背景圖、qq會員系統、qq等級系統、各種鑽、各種特權、頭像掛件、個性簽名、空間是否更新、最近常聽)
f) 查看用戶性別
而各個請求,可能又會去請求其他系統。
任何一個系統調用失敗,都可能會導致功能出現各種各樣的問題。
所以我們需要在異常信息中,傳遞一些必要信息,如 唯一請求編號、異常編碼、異常機器ip等必要信息。假如調用鏈路是 S –> M -> Z -> E -> A -> H ,一旦E出現了異常並返回給Z,根據異常里面包含的信息,便能馬上定位的機器,開始處理,而不是從鏈路的最開始一台一台機器去排查。
最后補一個問題,自定義異常處理了,那非自定義異常該怎么辦呢?