詳解SpringBoot異常處理流程及原理
異常處理流程
執(zhí)行目標(biāo)方法,目標(biāo)方法運(yùn)行期間有任何異常都會(huì)被catch捕獲,并標(biāo)志當(dāng)前請求結(jié)束,dispatchException拋出異常

進(jìn)入視圖解析流程,并渲染頁面,發(fā)生異常時(shí),參數(shù)mv為空,傳入捕獲的異常dispatchException

處理handler發(fā)生的異常,處理完成返回ModelAndView

(1)遍歷所有的HandlerExceptionResolvers,找到可以處理當(dāng)前異常的解析器來解析異常

(2)調(diào)用resolveException解析異常,傳入request和response對象,哪個(gè)方法,發(fā)生的異常,然后自定義異常處理返回ModelAndView

(3)系統(tǒng)默認(rèn)的異常解析器

① DefaultErrorAttributes先來處理異常,把異常信息保存到request域并返回null

② ExceptionHandlerExceptionResolver用來處理標(biāo)注了@ExceptionHandler注解的方法異常
③ ResponseStatusExceptionResolver用來處理標(biāo)注了@ResponseStatus注解的方法異常
④ DefaultHandlerExceptionResolver默認(rèn)的處理器異常解析器,處理一些常見的異常
(4)如果沒有任何解析器能夠處理異常,異常就會(huì)拋出

(5)如果沒有任何解析器能夠處理當(dāng)前異常,最終就會(huì)發(fā)送/error請求,將保存的異常信息轉(zhuǎn)發(fā)到/error。BasicErrorController專門來處理/error請求,BasicErrorController會(huì)遍歷所有的ErrorViewResolver解析錯(cuò)誤視圖,如果沒有自定義的錯(cuò)誤視圖解析器,就會(huì)使用默認(rèn)的DefaultErrorViewResolver,會(huì)把響應(yīng)碼作為錯(cuò)誤頁的地址,模板引擎最終響應(yīng)這個(gè)頁面。
幾種異常處理方式及原理
1.自定義錯(cuò)誤頁,error/404.html、error/5xx.html。有精確的錯(cuò)誤狀態(tài)碼頁面就匹配精確,沒有就找 4xx.html,如果都沒有就觸發(fā)白頁
2.使用@ControllerAdvice和@ExceptionHandler處理全局異常,底層是ExceptionHandlerExceptionResolver 支持的

3.使用@ResponseStatus和自定義異常。底層是 ResponseStatusExceptionResolver ,底層調(diào)用 response.sendError(statusCode, resolvedReason),Tomcat會(huì)收到一個(gè)error。請求最后new一個(gè)空的ModelAndView返回,這樣任何處理解析器都處理不了當(dāng)前的異常,最終就會(huì)發(fā)送/error請求,BasicErrorController專門來處理/error請求,適配4xx.html或者5xx.html頁面



4.Spring底層的異常,如參數(shù)類型轉(zhuǎn)換異常。底層是DefaultHandlerExceptionResolver 處理框架底層的異常,底層也是response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE),Tomcat會(huì)收到一個(gè)error。請求最后new一個(gè)空的ModelAndView返回,這樣任何處理解析器都處理不了當(dāng)前的異常,最終就會(huì)發(fā)送/error請求,BasicErrorController專門來處理/error請求,適配4xx.html或者5xx.html頁面
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.自定義實(shí)現(xiàn) HandlerExceptionResolver 處理異常,可以作為默認(rèn)的全局異常處理規(guī)則
@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 實(shí)現(xiàn)自定義處理異常。
(1)底層調(diào)用response.sendError時(shí) ,error請求就會(huì)默認(rèn)轉(zhuǎn)給basicErrorController,BasicErrorController專門來處理/error請求,適配4xx.html或者5xx.html頁面
(2)如果異常沒有任何解析器能處理,tomcat底層 也會(huì)調(diào)用response.sendError。error請求就會(huì)默認(rèn)轉(zhuǎn)給basicErrorController,BasicErrorController專門來處理/error請求,適配4xx.html或者5xx.html頁面。
(3)basicErrorController 要去的頁面地址是由 ErrorViewResolver這個(gè)錯(cuò)誤視圖解析器決定的,即適配4xx.html或者5xx.html頁面。
到此這篇關(guān)于詳解SpringBoot異常處理流程及原理的文章就介紹到這了,更多相關(guān)SpringBoot異常處理流程及原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot?2.x?RabbitTemplate默認(rèn)消息持久化的原因解析
這篇文章主要介紹了Springboot?2.x?RabbitTemplate默認(rèn)消息持久化的原因解析,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
Java數(shù)據(jù)結(jié)構(gòu)之棧與綜合計(jì)算器的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Java數(shù)據(jù)結(jié)構(gòu)中棧與綜合計(jì)算器的實(shí)現(xiàn),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2022-10-10
SpringSecurity+Mysql數(shù)據(jù)庫實(shí)現(xiàn)用戶安全登錄認(rèn)證的實(shí)踐
Spring Security 是一個(gè)提供身份認(rèn)證、授權(quán)和防范常見攻擊的安全權(quán)限框架,本文主要介紹了SpringSecurity+Mysql數(shù)據(jù)庫實(shí)現(xiàn)用戶安全登錄認(rèn)證的實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-08-08
springboot整合過濾器實(shí)戰(zhàn)步驟
在項(xiàng)目開發(fā)過程中,過濾器或者攔截器幾乎是必用的,他可以很方便的完成類似日志處理、token驗(yàn)證等一系列操作,區(qū)別于業(yè)務(wù)接口,獨(dú)立進(jìn)行處理,感覺就是一種Aop思想。下面模擬請求接口前的token驗(yàn)證,進(jìn)行過濾器的實(shí)戰(zhàn)2022-04-04

