“系統中每行代碼,都應該是有意義的,如果一段代碼可有可無,那它就不應該存在。”
01
—
內容簡述
異常處理是軟件開發的必備技能,但“異常處理,究竟是處理什么?”,很多小伙伴并沒有一個清晰的認識,大部分人的認識停留在給代碼加上try/catch就算是異常處理了,至于異常捕獲之后該做什么,并不清楚。本文闡述一下自己對異常處理的思考,希望幫助大家對異常處理有一個清晰的認識,在面對異常處理時,能夠有準確的決策。
02
—
區分異常和錯誤
首先要區分哪些是異常,哪些是錯誤。
可以預測,可以通過代碼邏輯避免發生的異常,我稱之為“錯誤”。
無法預測,無法通過代碼邏輯避免的異常,我稱之為“異常”。
相信到這里,很多小伙伴心里已經有答案了,比如,平時遇到最多的——空引用異常,應該算是錯誤,這是可以通過代碼邏輯避免的。而真正的異常是無法預料的,比如:網絡中斷、請求超時、堆棧溢出、第三方服務異常…等。
我們區分了異常和錯誤,那么對于屬于錯誤的部分,最佳的處理方案是通過代碼邏輯,盡量控制,避免錯誤的發生,而對于屬于異常的部分,或者遺漏的,沒有控制的錯誤,該如何處理?接下來便是本文的重點。
03
—
異常處理要做什么
異常處理概括起來要做三件事:
1.記錄異常日志
記錄異常日志是為了后續排查,定位,解決異常問題,需要記錄的信息包括:
異常發生時間,異常代碼位置,以及異常時上下文信息(參數),當前操作人等;
如果是Web請求,還要記錄請求的IP地址,URL,客戶端設備信息;
如果是SOA或微服務架構,還要記錄調用鏈路標識TraceID。
記錄異常信息的原則是:幫助開發人員還原異常現場,快速定位異常原因,以便盡快修復。
2.確保非托管資源的關閉和釋放
包括:數據庫鏈接,IO流,等非托管資源的處理,在發生異常的情況下,如何正確關閉鏈接,釋放資源,是需要重點考慮的。
推薦使用 using?語句聲明非托管資源,而不是用try/catch,可以查看我之前的文章?C# using()的本質
3.處理異常后續業務邏輯
主要是業務處理邏輯中事先規劃的異常發生后的處理邏輯,比如:
某個服務接口請求超時后進行重試;
某個功能操作失敗后,切換到備選方案(降級)或觸發補償事件;
在多線程中,當某個子線程異常之后,取消其他相關子線程操作;
自定義異常的處理。
上述情況要根據實際的業務場景決定,如果系統設計時并沒有規劃,也就不需求去處理這部分功能。
04
—
處理方案
明確了異常處理的三件事,接著看具體方案。
第一件事:記錄異常日志
毫無疑問,應該由全局異常處理組件記錄異常日志,如果框架有全局異常處理功能,就使用框架提供的異常處理功能,如果框架沒有,那就自己開發一個。在Asp.Net中,可以使用ExceptionFilter或自定義中間件實現全局異常處理。
第二件事:確保非托管資源關閉和釋放
由上文所說,使用using就好。
第三件事:處理異常后續業務邏輯
視實際業務場景而定,可以在代碼中加try/catch,也可以開發通用的異常處理組件,讓業務邏輯更簡潔清晰。
05
—
總結
異常處理規范建議:
通過代碼規范,盡量減少系統中可控的異常(錯誤)發生。
通過全局異常組件,記錄異常日志,處理通用異常。
僅在業務邏輯明確需求的情況下,使用try/catch處理異常。
06
—
成長軌跡
有小伙伴,習慣在每個方法中都加try/catch,卻說不清為何這么做,大概的理由是:程序總難免會報錯,所以要進行try/catch。根本原因在于:對代碼運行機制不夠理解,對自己的代碼沒有信心,以及對異常處理認識的模糊。這些try/catch是不應該出現的,會對代碼簡潔性,可讀性造成污染,與優雅代碼背道而馳。我自己也是從這個階段過來的,也希望小伙伴們不要一直停留在這個階段。
我第一次對異常處理有深刻認知是得到了一位微軟首席架構師的指點,這位架構師是沈征,一位大師級的技術專家,既能講理論,畫架構圖,又能寫出優雅的框架代碼,是我多年職業生涯中遇到的為數不多的大師,他的幾句話足以讓人在迷霧之中看清前方的路,看見遠方的山,看到頭頂的太陽和藍天,再次向大師致敬。
認為內容有價值的話可以點贊,轉發,關注