SpringBoot Web開發(fā)中的異常處理自動(dòng)配置原理解析
默認(rèn)規(guī)則
1. 默認(rèn)情況下,SpringBoot提供/error處理所有錯(cuò)誤的映射
2. 對(duì)于機(jī)器客戶端,它將生成JSON響應(yīng),其中包含錯(cuò)誤,HTTP狀態(tài)和異常消息的詳細(xì)信息
- 例如postman發(fā)送請(qǐng)求

3. 對(duì)于瀏覽器客戶端,響應(yīng)一個(gè)“whitelabel”錯(cuò)誤視圖,以HTML格式呈現(xiàn)相同的數(shù)據(jù)

4. 自定義錯(cuò)誤視圖解析規(guī)則
- 完全替換默認(rèn)行為,可以實(shí)現(xiàn) ErrorController 并注冊(cè)該類型的Bean定義,或添加ErrorAttributes類型的組件
定制錯(cuò)誤處理邏輯
1. 自定義錯(cuò)誤頁(yè)
- 替換默認(rèn)的“whitelabel”錯(cuò)誤視圖,在templates在創(chuàng)建error文件夾,定義404和5xx的視圖error/404.html error/5xx.html
- 有精確的錯(cuò)誤狀態(tài)碼頁(yè)面就匹配精確,沒(méi)有就找4xx.html或者N(錯(cuò)誤狀態(tài)碼首數(shù)字)xx.html;如果都沒(méi)有就觸發(fā)白頁(yè)

2. 方法一:@ExceptionHandler處理異常
- 注解用來(lái)定義一個(gè)或多個(gè)具體的異常類型,發(fā)生異常時(shí)由此處理
- @ControllerAdvice+@ExceptionHandler處理全局異常
- 底層是 ExceptionHandlerExceptionResolver 支持的
/**
* 處理整個(gè)web controller的異常
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
//定義可以處理的異常
@ExceptionHandler({ArithmeticException.class,
NullPointerException.class})
public String handleArithException(Exception e){
log.error("異常是:{}",e);
//返回視圖地址,也可以返回ModelAndView
return "login";
}
}3. 方法二:@ResponseStatus+自定義異常
- 指定發(fā)生異常時(shí)的響應(yīng)狀態(tài)碼,自定義異常類型
- 底層是 ResponseStatusExceptionResolver
- 把ResponseStatus注解的信息組裝成ModelAndView返回
- 底層調(diào)用 response.sendError(statusCode, resolvedReason);
- tomcat發(fā)送的/error
//異常響應(yīng)狀態(tài)碼+異常原因
@ResponseStatus(value= HttpStatus.FORBIDDEN,reason = "用戶數(shù)量太多")
public class UserTooManyException extends RuntimeException {
public UserTooManyException(){
}
public UserTooManyException(String message){
super(message);
}
}4. Spring底層的異常
- 如參數(shù)類型轉(zhuǎn)換異常
- DefaultHandlerExceptionResolver 處理框架底層的異常
- 解析異常時(shí)做了一系列異常類型的判斷
- 每個(gè)異常處理都會(huì)執(zhí)行response.sendError(.....),tomcat發(fā)送/error請(qǐng)求
- 如果還是解析不了,就會(huì)響應(yīng)tomcat的錯(cuò)誤頁(yè)面

5. 方法三:自定義實(shí)現(xiàn) HandlerExceptionResolver 處理異常
- @Order(value = Ordered.HIGHEST_PRECEDENCE) 將優(yōu)先級(jí)設(shè)為最高
- 如果不加優(yōu)先級(jí),默認(rèn)是排列在自動(dòng)配置的異常處理器之后,若默認(rèn)的處理器可以處理異常,故自定義的異常處理器不會(huì)生效
- 調(diào)用response.sendError(.....),tomcat發(fā)送/error請(qǐng)求
//優(yōu)先級(jí),數(shù)字越小優(yōu)先級(jí)越高
@Order(value= Ordered.HIGHEST_PRECEDENCE)
@Component
public class CustomerHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
try {
//狀態(tài)碼+異常信息
response.sendError(511,"我喜歡的錯(cuò)誤");
} catch (IOException e) {
e.printStackTrace();
}
return new ModelAndView();
}
}6. 關(guān)于response.sendError()
- 自己調(diào)用response.sendError(),請(qǐng)求會(huì)被轉(zhuǎn)發(fā)給basicErrorController進(jìn)行處理
- 如果自己沒(méi)有調(diào)用,并且異常沒(méi)有任何人能夠處理,tomact底層會(huì)自動(dòng)調(diào)用response.sendError()將請(qǐng)求轉(zhuǎn)發(fā)給basicErrorController處理。
- 總之,三種方法最后都會(huì)調(diào)用sendError()轉(zhuǎn)交給basicErrorController處理,ErrorViewResolver進(jìn)行解析,最后會(huì)轉(zhuǎn)到一個(gè)頁(yè)面或者返回json數(shù)據(jù)。
異常處理自動(dòng)配置原理
- ErrorMvcAutoConfiguration 自動(dòng)配置異常處理規(guī)則
1. 綁定配置文件的server 和 spring.mvc

2. 自動(dòng)添加組件:類型:DefaultErrorAttributes -> id:errorAttributes
- DefaultErrorAttributes:定義錯(cuò)誤頁(yè)面中可以包含哪些數(shù)據(jù)
- DefaultErrorAttributes implements ErrorAttributes,HandlerExceptionResolver
- 自定義錯(cuò)誤頁(yè)面屬性



3. 自動(dòng)添加組件:類型:BasicErrorController --> id:basicErrorController
- 可以通過(guò)BasicErrorController 自定義頁(yè)面跳轉(zhuǎn)邏輯
- 處理默認(rèn) /error 路徑的請(qǐng)求;頁(yè)面響應(yīng) new ModelAndView("error", model),
- 要么響應(yīng)一個(gè)HTML頁(yè)面,要么響應(yīng)一個(gè)json


- 容器中有組件 View->id是error;(響應(yīng)默認(rèn)錯(cuò)誤頁(yè))


- 容器中放組件 BeanNameViewResolver(視圖解析器);按照返回的視圖名作為組件的id去容器中找View對(duì)象

4. 自動(dòng)添加組件:類型:DefaultErrorViewResolver -> id:conventionErrorViewResolver
- 如果發(fā)生錯(cuò)誤,會(huì)以HTTP的狀態(tài)碼 作為視圖名字(viewName),找到真正的頁(yè)面
- 比如error/404、5xx.html



異常處理步驟流程
- 舉例,執(zhí)行一個(gè)controller方法,除數(shù)為0拋出異常
1. doDispatch()中執(zhí)行controller目標(biāo)方法
- 目標(biāo)方法運(yùn)行期間有任何異常都會(huì)被catch、而且標(biāo)志當(dāng)前請(qǐng)求結(jié)束
- 并且將異常賦值給 dispatchException
- 即使目標(biāo)方法發(fā)生異常,也執(zhí)行視圖解析流程

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

- 遍歷所有的 handlerExceptionResolvers,看誰(shuí)能處理當(dāng)前異常【HandlerExceptionResolver處理器異常解析器】
- DefaultErrorAttributes先來(lái)處理異常,把異常信息保存到request域,并且返回null
- 然后交由HandlerExceptionResolverComposite,遍歷其中的異常處理器處理,但此例子默認(rèn)無(wú)法處理
- ExceptionHandlerExceptionResolver,使用注解@ExceptionHandler才能由此解析處理
- ResponseStatusExceptionHandler,使用注解@ResponseStatus才能由此解析處理


3. 默認(rèn)無(wú)法處理目標(biāo)方法異常時(shí),異常會(huì)被拋出
- 底層就會(huì)發(fā)送 /error 請(qǐng)求,會(huì)被BasicErrorController處理

- 解析錯(cuò)誤視圖;遍歷所有的 ErrorViewResolver 看誰(shuí)能解析

4. 模板引擎響應(yīng)出錯(cuò)誤視圖
- 默認(rèn)的 DefaultErrorViewResolver ,作用是把響應(yīng)狀態(tài)碼作為錯(cuò)誤頁(yè)的地址,error/500.html
- 查找順序:
- '/templates/error/500.html' >
- '/static/error/500.html' >
- '/templates/error/5xx.html' >
- '/static/error/5xx.html'

相關(guān)文章
SpringBoot下使用MyBatis-Puls代碼生成器的方法
這篇文章主要介紹了SpringBoot下使用MyBatis-Puls代碼生成器的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
SpringBoot整合Swagger接口文檔工具的流程步驟
我們?cè)陂_發(fā)接口的時(shí)候,會(huì)將接口文檔給前端的開發(fā)者進(jìn)行對(duì)接,我們可以通過(guò)Postman或者Yapi等接口管理工具進(jìn)行編寫管理,實(shí)際開發(fā)中,接口的管理確實(shí)也應(yīng)該通過(guò)專業(yè)的工具管理,本文,我們就來(lái)談?wù)勗趺丛赟pringBoot整合Swagger接口文檔工具2023-08-08
Spring Cloud Ribbon客戶端詳細(xì)介紹
Spring Cloud Ribbon 是一套基于 Netflix Ribbon 實(shí)現(xiàn)的客戶端負(fù)載均衡和服務(wù)調(diào)用工具。通過(guò)Spring Cloud的封裝,可以讓我們輕松地將面向服務(wù)的REST模版請(qǐng)求自動(dòng)轉(zhuǎn)換成客戶端負(fù)載均衡的服務(wù)調(diào)用2022-09-09
SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能
最近有一個(gè)需求是關(guān)于視頻上傳播放的,需要設(shè)計(jì)一個(gè)方案,中間談到了Minio這個(gè)技術(shù),于是來(lái)學(xué)習(xí)一下,所以本文給大家介紹了SpringBoot整合Minio實(shí)現(xiàn)文件上傳和讀取功能,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-07-07
Spring Boot 2 實(shí)戰(zhàn):自定義啟動(dòng)運(yùn)行邏輯實(shí)例詳解
這篇文章主要介紹了Spring Boot 2 實(shí)戰(zhàn):自定義啟動(dòng)運(yùn)行邏輯,結(jié)合實(shí)例形式詳細(xì)分析了Spring Boot 2自定義啟動(dòng)運(yùn)行邏輯詳細(xì)操作技巧與注意事項(xiàng),需要的朋友可以參考下2020-05-05
spring boot整合netty的實(shí)現(xiàn)方法
這篇文章主要介紹了spring boot整合netty的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08

