執行目標方法,目標方法運行期間有任何異常都會被catch
捕獲,並標誌當前請求結束,dispatchException
拋出異常
進入視圖解析流程,並渲染頁面,發生例外狀況時,參數mv
為空,傳入擷取的例外dispatchException
處理handler
發生的異常,處理完成返回ModelAndView
(1)遍歷所有的HandlerExceptionResolvers
#,找到可以處理目前例外的解析器來解析異常
(2)呼叫 resolveException
解析異常,傳入request
和response
對象,哪個方法,發生的異常,然後自訂異常處理返回ModelAndView
#(3)系統預設的例外解析器
#① DefaultErrorAttributes
先來處理異常,把異常資訊保存到request
網域並傳回null
② ExceptionHandlerExceptionResolver
用來處理標註了@ExceptionHandler
註解的方法異常
③ ResponseStatusExceptionResolver
用來處理標註了@ResponseStatus
註解的方法例外
#CC😢 #DefaultHandlerExceptionResolver預設的處理器異常解析器,處理一些常見的異常
(4)如果沒有任何解析器能夠處理異常,異常就會拋出
#(5)如果沒有任何解析器能夠處理當前異常,最終就會發送
/error
請求,將已儲存的異常訊息轉送到/error
。 BasicErrorController
專門來處理
會遍歷所有的ErrorViewResolver
解析錯誤視圖,如果沒有自訂的錯誤視圖解析器,就會使用預設的DefaultErrorViewResolver
,會把回應碼當作錯誤頁的位址,模板引擎最終會回應這個頁面。 幾種異常處理方式及原理
1.自訂錯誤頁,error/404.html
、error/5xx.html
。有精確的錯誤狀態碼頁面就匹配精確,沒有就找 4xx.html
,如果都沒有就觸發白頁
2.使用@ControllerAdvice
和@ExceptionHandler處理全域異常,底層是
ExceptionHandlerExceptionResolver 支援的
3.使用
@ResponseStatus
和自定義異常。底層是 ResponseStatusExceptionResolver
,底層呼叫 response.sendError(statusCode, resolvedReason)
,Tomcat會收到一個error
#。請求最後new
一個空的ModelAndView
返回,這樣任何處理解析器都處理不了當前的異常,最終就會發送/error
請求,
專門處理/error
請求,適配
或5xx.html
頁面##4.Spring底層的異常,如參數類型轉換異常。底層是
DefaultHandlerExceptionResolver
處理框架底層的例外,底層也是
protected ModelAndView doResolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { try { if (ex instanceof HttpRequestMethodNotSupportedException) { return handleHttpRequestMethodNotSupported( (HttpRequestMethodNotSupportedException) ex, request, response, handler); } else if (ex instanceof HttpMediaTypeNotSupportedException) { return handleHttpMediaTypeNotSupported( (HttpMediaTypeNotSupportedException) ex, request, response, handler); } else if (ex instanceof HttpMediaTypeNotAcceptableException) { return handleHttpMediaTypeNotAcceptable( (HttpMediaTypeNotAcceptableException) ex, request, response, handler); } else if (ex instanceof MissingPathVariableException) { return handleMissingPathVariable( (MissingPathVariableException) ex, request, response, handler); } else if (ex instanceof MissingServletRequestParameterException) { return handleMissingServletRequestParameter( (MissingServletRequestParameterException) ex, request, response, handler); } else if (ex instanceof ServletRequestBindingException) { return handleServletRequestBindingException( (ServletRequestBindingException) ex, request, response, handler); } else if (ex instanceof ConversionNotSupportedException) { return handleConversionNotSupported( (ConversionNotSupportedException) ex, request, response, handler); } else if (ex instanceof TypeMismatchException) { return handleTypeMismatch( (TypeMismatchException) ex, request, response, handler); } else if (ex instanceof HttpMessageNotReadableException) { return handleHttpMessageNotReadable( (HttpMessageNotReadableException) ex, request, response, handler); } else if (ex instanceof HttpMessageNotWritableException) { return handleHttpMessageNotWritable( (HttpMessageNotWritableException) ex, request, response, handler); } else if (ex instanceof MethodArgumentNotValidException) { return handleMethodArgumentNotValidException( (MethodArgumentNotValidException) ex, request, response, handler); } else if (ex instanceof MissingServletRequestPartException) { return handleMissingServletRequestPartException( (MissingServletRequestPartException) ex, request, response, handler); } else if (ex instanceof BindException) { return handleBindException((BindException) ex, request, response, handler); } else if (ex instanceof NoHandlerFoundException) { return handleNoHandlerFoundException( (NoHandlerFoundException) ex, request, response, handler); } else if (ex instanceof AsyncRequestTimeoutException) { return handleAsyncRequestTimeoutException( (AsyncRequestTimeoutException) ex, request, response, handler); } } catch (Exception handlerEx) { if (logger.isWarnEnabled()) { logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", handlerEx); } } return null; }
5.自訂實作 HandlerExceptionResolver
處理異常,可以作為預設的全域例外處理規則
@Order(value = Ordered.HIGHEST_PRECEDENCE) @Component public class CustomerHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { try { response.sendError(521,"I love you !"); } catch (IOException e) { e.printStackTrace(); } return new ModelAndView(); } }
ErrorViewResolver
實作自訂處理異常。
(1)底層呼叫response.sendError
時,error
要求就會預設轉給basicErrorController
,BasicErrorController
專門處理/error
請求,適配器4xx.html
或5xx.html
頁面
(2)如果異常沒有任何解析器能處理,tomcat底層也會呼叫response.sendError
。 error
請求就會預設轉給basicErrorController
,BasicErrorController
專門處理/error
請求,適配4xx.html
或5xx.html
頁。
(3)basicErrorController
要去的頁面位址是由 ErrorViewResolver
這個錯誤視圖解析器決定的,也就是適應4xx.html
或5xx.html
頁。
以上是SpringBoot異常處理的原理分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!