能夠搜索微信公衆號【Jet 與編程】查看更多精彩文章spring
在上篇【連接】中介紹了 Spring Boot 全局異常處理的一種方式,但那是一種全局性的容錯機制,目的是把 Spring Boot 默認的 ErrorController 替換掉,從而更友好地展現自定義的異常信息給客戶端。編程
固然,除了這種全局的容錯機制,有時候咱們更但願對 Controller 層指定的異常進行特殊的處理,更甚至說這是異常處理的一種標準手段,即業務層的異常直接向上拋便可,不用本身處理,而後由 Controller 層進行統一的異常處理。微信
說明:本文的全局異常處理,一樣能夠抽象地理解成:全局處理 Controller 層拋出的異常spring-boot
Spring 給咱們提供的兩種實現的方式:spa
局部異常處理:@Controller + @ExceptionHandler設計
全局異常處理:@ControllerAdvice + @ExceptionHandler代理
此處的局部和全局的區別在於:code
當代理方法出如今 @Controller 註解的類中時,則此方法會代理此 Controller 中的異常。cdn
當代理方法出如今 @ControllerAdvice 註解的類中時,則此方法會代理全部 Controller 中的異常。繼承
局部異常處理,咱們只須要在 @Controller 註解的類中寫一個自定義的異常處理方法,而後給這個方法添加 @ExceptionHandler 註解便可,效果就是當此類中的方法有未捕獲的異常拋出時,異常會以參數的形式傳遞給這個異常處理方法,咱們只須要在此方法中進行相關的異常處理便可。
//局部異常處理(ps:對於參數必填的400異常也會被此異常處理器捕獲)
@ExceptionHandler(Exception.class)
public String exHandler(Exception e) {
if(e instanceof ArithmeticException) {
return "除0異常-局部捕獲";
}
if(e instanceof STCRException) {
return "自定義異常-局部捕獲";
}
// 未知的異常作出響應
return "未知異常-局部捕獲";
}
複製代碼
上述方法會處理全部的異常(由於參數是 Exception),固然,咱們也能夠根據異常的不一樣,來編寫多個方法分別處理對應的異常(實現的過程只須要參數傳遞不一樣的異常類型便可)。
可是咱們不可能在全部的類中都寫一遍異常的處理方法,因此此處有兩個思路:
思路一:抽取異常處理代碼作成基類,而後由每一個須要異常處理的 Controller 類去繼承 缺點:類的繼承機制,實際上是一種概念上的屬性的繼承,此處僅僅是爲了得到一個公共方法而去作異常類的繼承,顯然破壞了代碼的優雅性。再言之,類是隻能繼承一次的,這樣作有可能會破壞代碼結構的設計。
思路二:抽取代碼作成接口,而後由每一個須要異常處理的 Controller 類去實現這個接口便可 這種思路得益於 Java8 的 Functional Interface,便可用在接口中寫一個默認方法,此方法中是能夠寫具體的實現的。 缺點:對環境的要求有些苛刻,即要求 JDK 的版本至少爲 1.8,在某些應用中,顯然是不合適的。
最後,不管是哪一種抽取基類的實現,都是存在侷限性的,由於這都要求咱們去繼承或實現該基類,顯然這不是咱們想要的,咱們想要的是那種一勞永逸的實現方式。
全局異常處理,其實很簡單,咱們只須要寫一個配置類,在該類上添加註解 @ControllerAdvice,而後在該類中異常處理方法便可,同上文的局部異常處理方法。
效果是該類中的異常處理方法會自動處理全部 Controller 中拋出的異常,這纔是知足咱們需求的異常處理方式。
@ControllerAdvice
public class GlobalExceptionHandler {
//處理自定義的異常
@ExceptionHandler(STCRException.class)
@ResponseBody
public Object customHandler(STCRException e) {
return "自定義異常-全局";
}
//其餘未處理的異常
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(Exception e) {
return "其它異常-全局";
}
}
複製代碼
好了,咱們先整理一下異常的處理流程,最外層的異常處理由 Spring 的全局異常 ErrorController 來接管,這實際上是在過濾器層面進行的異常處理,內層由 @ExceptionHandler 處理全部 Controller 拋出的異常。
好比 404 異常,還沒有進入 Controller 層,因此異常由 ErrorController 捕獲處理。
好比 必填的參數缺失(400)異常,由於已經進入了 Controller 層,全部異常由 ExceptionHandler 捕獲處理。
注:局部異常的優先級是高於全局異常的