線上問題
近期在線上系統中遇到了一個奇怪的問題,某個請求處理失敗了,但是日誌裏沒有任何錯誤信息,catch(Exception e) {}
代碼塊根本沒有執行,因此直接跳過了錯誤處理邏輯,但是finally{}
塊卻執行了。根據此現象我們推測出很可能是代碼塊拋出了非Exception
子類的異常。果然,將catch Exception
改爲catch Throwable
後, 日誌中出現了java.lang.IncompatibleClassChangeError
異常。因爲此異常是Error
而不是Exception
的子類,所以導致了出現catch{}
沒有執行但finally
執行了的現象。
關於Exception
在很多入門書上都會有類似於"Exception是可恢復的而Error往往是不可恢復的系統嚴重錯誤"這樣的內容,當然,這句話本身是沒問題的,問題在於即便是Error錯誤我們也應該捕獲一下,至少要記一下日誌,如果忽略掉的話就會出現上面這種莫名其妙失敗但又找不到線索的情況。
經查,報java.lang.IncompatibleClassChangeError
的原因是最近一次上線時引入了新的業務jar包,此依賴的某個傳遞依賴版本跟原有系統中的jar版本有衝突,導致JVM在執行時報錯。這個問題之所以在測試時沒有發現,還有一個原因,就是只有在執行到特定邏輯時纔會觸發,並不是每次都會出現,非常隱蔽。
如果偶爾看過Netty的代碼,你會發現Netty所有的catch, 最後都是以catch(Throwable e)
結尾的,而不是Exception
。我們在編碼時也應該以catch Throwable
兜底, 不要再使用Exception
了。