Spring Boot 全局異常處理(下)

能夠搜索微信公衆號【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 捕獲處理。

注:局部異常的優先級是高於全局異常的

相關文章
相關標籤/搜索