天天看點

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

錯誤場景

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

驗證請求的Token合法性的Filter。Token校驗失敗時,直接抛自定義異常,移交給Spring處理:

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正
阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正
阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

測試HTTP請求:

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

日志輸出如下:說明IllegalRequestExceptionHandler未生效。

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

why?

這就需要精通Spring異常處理流程了。

解析

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

當所有Filter被執行完畢,Spring才會處理Servlet相關,而DispatcherServlet才是整個Servlet處理核心,它是前端控制器設計模式,提供 Spring Web MVC 的集中通路點并負責職責的分派。

在這,Spring處理了請求和處理器的對應關系及統一異常處理。

Filter内異常無法被統一處理,就是因為異常處理發生在 DispatcherServlet#doDispatch()

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

但此時,過濾器已全部執行完。

Spring異常統一處理

ControllerAdvice如何被Spring加載并對外暴露?

WebMvcConfigurationSupport#handlerExceptionResolver()

執行個體化并注冊一個ExceptionHandlerExceptionResolver 的執行個體

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

最終按下圖調用棧,Spring 執行個體化了ExceptionHandlerExceptionResolver類。

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

ExceptionHandlerExceptionResolver實作了InitializingBean

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

重寫 afterPropertiesSet()

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

initExceptionHandlerAdviceCache

完成所有 ControllerAdvice 中的ExceptionHandler 初始化:查找所有 @ControllerAdvice 注解的 Bean,把它們放入exceptionHandlerAdviceCache。

這裡即指自定義的IllegalRequestExceptionHandler

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正
阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

所有被 @ControllerAdvice 注解的異常處理器,都會在 ExceptionHandlerExceptionResolver 執行個體化時自動掃描并裝載在其exceptionHandlerAdviceCache。

initHandlerExceptionResolvers

當第一次請求發生時,DispatcherServlet#initHandlerExceptionResolvers() 将擷取所有注冊到 Spring 的 HandlerExceptionResolver 執行個體(ExceptionHandlerExceptionResolver正是),存到handlerExceptionResolvers

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正
阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

ControllerAdvice如何被Spring消費并處理異常?

DispatcherServlet

doDispatch()

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

執行使用者請求時,當查找、執行請求對應的 handler 過程中異常時:

  1. 會把異常值賦給 dispatchException
  2. 再移交 processDispatchResult()

processDispatchResult

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

當Exception非空時,繼續移交

processHandlerException

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

從 handlerExceptionResolvers 擷取有效的異常解析器以解析異常。

這裡的 handlerExceptionResolvers 一定包含聲明的IllegalRequestExceptionHandler#IllegalRequestException 的異常處理器的 ExceptionHandlerExceptionResolver 包裝類。

修正

為利用到 Spring MVC 的異常處理機制,改造Filter:

  • 手動捕獲異常
  • 将異常通過 HandlerExceptionResolver 進行解析處理

據此,修改 PermissionFilter,注入 HandlerExceptionResolver:

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

然後,在 doFilter 捕獲異常并移交 HandlerExceptionResolver:

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

現在再用錯誤 Token 請求,日志輸出如下:

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正

響應體:

阿裡四面:Spring Exception的原理你精通了嗎?錯誤場景解析Spring異常統一處理修正