spring-boot 統一異常捕獲
java異常介紹
異常時相對於return的一種退出機制,可以由系統觸發,也可由程式通過throw語句觸發,異常可以通過try/catch語句進行捕獲並處理,如果沒有捕獲,則會導致程式退出並輸出異常棧資訊,異常有不同的型別,所有異常類都有一個共同的父類Throwable,下面我們先從Throwable開始介紹。
Throwable
Throwable
是所有異常類的父類,有四個構造方法
public Throwable(Throwable cause)
public Throwable(String message, Throwable cause)
public Throwable(String message)
public Throwable()
主要有兩個類,一個是message,表示異常的訊息,一個是cause,表示觸發該異常的其他異常,異常可以形成一個異常鏈,上層的異常由底層到的異常觸發,cause表示底層異常。
異常體系
java定義了非常多的異常類,來表示各種型別的異常,下面的圖示是部分的異常類:
Throwable是所有異常類的基類,它有兩個子類:Error和Exception。
- Error錯誤
作業系統或者虛擬機器發生的錯誤,這個時候程式是跑不起來的,程式碼是無法處理的,一般表示系統錯誤或者資源耗盡,由java系統自己處理,比如圖示中給出的:虛擬機器錯誤、棧溢位、記憶體溢位等錯誤
- Exception
表示應用程式錯誤,是可以通過程式碼處理的,有兩大類:一類是受檢異常(checked exception),一類是非受檢異常(uncheck exception),也就是runtime異常,他兩的區別就在於java是如何對待他們的,受檢異常,java會要求強制進行處理,不然編譯時不通過的,對於非受檢異常則沒有這個強制性的要求。
解釋
該怎麼理解受檢異常和非受檢異常呢,我的理解就是做某件事的時候我們能夠順利的按照我們預期的做完,但是實際上呢可能會出現各種各樣的情況,這種可能出現的情況就把他稱之為異常,這種異常有的我們能處理,有的我們不能處理,能處理的就把它稱作為受檢異常,不能處理的稱作為非受檢異常。
比如說,客戶端傳送一個請求,要查詢資料庫,那有可能找到有可能沒找到,沒找到的話,就應該丟擲runtime異常,再比如要去讀取檔案,檔案可能是不存在的,那就應該丟擲checked exception,這其實就是bug,我們應該去處理的。
怎麼理解呢,比如讀取檔案,當檔案不存在,發生異常,能處理麼,當然可以處理啊,怎麼處理,把檔案路徑改成正確的不就行了。從某種意義上來說,checked異常是真正的bug
沒有辦法處理的情況,比如說使用者輸入ID為2,查詢記錄能找到,但是如果輸入2000就找不到了,這裡的找不到就是一種異常情況,就需要產生一個執行時異常也就是非受檢異常。
已知異常和未知異常
上面我們提到的受檢異常 unchecked exception
和執行時異常 RuntimeException
都是從java語法層面來說的,那從程式開發者的角度來說,分為兩類:已知異常和未知異常。
已知異常和未知異常,其實就在於我們程式設計師是否主動的去處理異常。
- 未知異常:當程式碼中未對一些情況做出處理而引發的異常,這就是未知異常,一般這種異常都是因為服務端的程式碼寫的有問題的,對於前段開發或者使用者,都是無意義的,記錄日誌供自己檢視就行了。
- 已知異常:更多的時候表示的是一種訊息,用來提示使用者的輸入是否有問題,只不過這裡我們用異常的形式來處理,當然也可以通過其他方式處理,比如當做結果去返回,也是可以的,但是這種方式不如全部都看做異常,通過全域性的異常處理器直接處理來的簡單。
Spring-Boot全域性異常處理器
在使用spring-boot進行開發到的時候,有時我們需要對程式中丟擲的異常進行統一的處理,spring-boot預留了響應的擴充套件點,我們只需要按照要求的方式去自定義自己的實現即可。
@ControllerAdvice
public class GlobalExceptionAdvice {
@ExceptionHandler(value = Exception.class)
public void handleHttpException(HttpServletRequest req, Exception ex){
}
}
@ControllerAdvice
表明GlobalExceptionAdvice是一個異常的處理類,具體的處理方法通過 @ExceptionHandler
進行標記,通過value來指定能夠處理的異常型別。異常的處理方法需要傳入兩個引數,一個是HttpServletRequest請求物件,可以從這裡獲取請求相關的一些資訊,比如請求的url或者引數等,另一個是Exception就是丟擲的異常。
模擬異常發生
我們在異常的處理方法中列印一條語句
@ControllerAdvice
public class GlobalExceptionAdvice {
@ExceptionHandler(value = Exception.class)
public void handleHttpException(HttpServletRequest req, Exception ex){
System.out.println("發生異常了");
}
}
然後再Controller裡丟擲一個異常
@RestController
public class BannerController {
@RequestMapping(value = "/v2/banner", method = {RequestMethod.GET})
public String test() throws Exception {
throw new Exception("我丟擲來的");
}
}
啟動程式後在瀏覽器中訪問路由,可以看到在控制檯中列印出了預期的資訊
當然在實際開發中,我們可能要多異常進行區分,該丟擲什麼型別的異常,異常處理函式可也不只一個,還要對返回的異常資訊進行自定義。
自定義異常類
當我們需要自定義異常類的時候,是該繼承自exception呢,還是繼承RuntimeException?下面我們就來討論一下。
當使用者訪問一個不存在的資源的時候,很明顯這種情況我們是處理不了的,而且這種情況我們是可以判斷出來的,所以這裡應該使用Runtime異常。
HttpException
是所有自定義執行時異常類的基類,這裡定義兩個狀態碼,一個code是我們業務層面的定義,一個httpStatusCode是http請求的,資源不存在的異常定義為 NotFoundException
在controller裡面丟擲這個異常,
那之前定義的 GlobalExceptionAdvice
能夠監聽到這個異常呢?
當然能,NotFoundException
是 HttpException
的子類,HttpException
是 RuntimeException
的子類,RuntimeException
又是 Exception
的子類,@ExceptionHandler(value = Exception.class)
全域性異常處理器裡指定的能夠處理的異常類是 Exception
自然也能處理 NotFoundException
。
但是這裡也有不同的地方,我們自定義的 HttpException
是多了兩個擴充套件欄位的,code
和 httpStatusCode
,所以在全域性異常處理器裡需要對異常的型別進行判斷,如果是自定義的就需要新增這兩個欄位。
這裡呢有兩種方式進行處理:一種是在之前的異常處理方法裡面,進行型別判斷,另一種呢是可以再新增一個異常處理方法,專門處理自定義異常類
這裡我們可以考慮一下,當我們丟擲 NotFoundException
異常的時候,是會進入哪一個異常處理方法裡?還是說兩個都進呢?
我們可以來試驗一下,啟動程式後,看看在控制檯列印的是什麼
在瀏覽器裡訪問路由以後,控制檯顯示了handleHttpException異常處理方法裡到的列印語句輸出的內容。
可以看到多個異常處理方法時可以同時存在的,各自處理自己所能處理的異常類。
更多內容,請移步個人部落格
相關文章
- 捕獲 React 異常React
- iOS異常捕獲iOS
- python異常捕獲Python
- android 異常捕獲-UncaughtExceptionHandlerAndroidException
- 記錄Javascript 異常捕獲JavaScript
- PHP使用trycatch,捕獲異常PHP
- 【筆記】forall 異常捕獲筆記
- 前端異常捕獲與上報前端
- PLSQL宣告部分異常捕獲SQL
- wpf 捕獲全域性異常
- 儲存過程——異常捕獲&列印異常資訊儲存過程
- python中如何捕獲異常Python
- JS 使用try catch捕獲異常JS
- Auth 授權的異常捕獲
- 異常的捕獲及處理
- python動態捕獲異常Python
- oracle異常捕獲程式碼(轉)Oracle
- 10. 異常捕獲、生成式
- IOS系統閃退異常(Crash)捕獲處理iOS
- 談談前端異常捕獲與上報前端
- DRF之異常捕獲原始碼分析原始碼
- 捕獲不到異常嘗試除以0
- 前端JavaScript 常見的報錯及異常捕獲前端JavaScript
- 異常處理機制(二)之異常處理與捕獲
- SpringBoot之全域性捕獲異常Spring Boot
- 在 C++ 中捕獲 Python 異常C++Python
- iOS 日誌重定向和異常捕獲iOS
- C#中有關異常的捕獲演示C#
- Android 全域性異常捕獲之CrashHandlerAndroid
- 如何自定義一個全域性異常捕獲器-SpiderManIDE
- Auto.js Pro 資料獲取 與 異常捕獲JS
- 前端開發中的Error以及異常捕獲前端Error
- Java捕獲非檢查異常----UncaughtExceptionHandler的使用JavaException
- 【Spring Cloud】Feign呼叫異常觸發降級後如何捕獲異常SpringCloud
- 記錄使用 guzzlehttp 異常捕獲踩坑記錄HTTP
- Flutter異常捕獲和Crash崩潰日誌收集Flutter
- Java 多執行緒異常捕獲Runnable實現Java執行緒
- MySQL儲存過程中捕獲異常的方法MySql儲存過程