日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 單片機(jī) > 架構(gòu)師社區(qū)
[導(dǎo)讀]目錄前言SpringBoot版本全局統(tǒng)一異常處理的前世今生SpringBoot的異常如何分類?如何統(tǒng)一異常處理?異常匹配的順序是什么?總結(jié)前言軟件開發(fā)過程中難免遇到各種的BUG,各種的異常,一直就是在解決異常的路上永不停歇,如果你的代碼中再出現(xiàn)try(){...}catch(){...

目錄

  • 前言
  • Spring Boot 版本
  • 全局統(tǒng)一異常處理的前世今生
  • Spring Boot的異常如何分類?
  • 如何統(tǒng)一異常處理?
  • 異常匹配的順序是什么?
  • 總結(jié)

前言

軟件開發(fā)過程中難免遇到各種的BUG,各種的異常,一直就是在解決異常的路上永不停歇,如果你的代碼中再出現(xiàn)try(){...}catch(){...}finally{...}代碼塊,你還有心情看下去嗎?自己不覺得惡心嗎?

冗余的代碼往往回喪失寫代碼的動力,每天搬磚似的寫代碼,真的很難受。今天這篇文章教你如何去掉滿屏的try(){...}catch(){...}finally{...},解放你的雙手。

Spring Boot 版本

本文基于的Spring Boot的版本是2.3.4.RELEASE。

全局統(tǒng)一異常處理的前世今生

早在Spring 3.x就已經(jīng)提出了@ControllerAdvice,可以與@ExceptionHandler、@InitBinder、@ModelAttribute 等注解注解配套使用,這幾個此處就不再詳細(xì)解釋了。

這幾個注解小眼一瞟只有@ExceptionHandler與異常有關(guān)啊,翻譯過來就是異常處理器。其實異常的處理可以分為兩類,分別是局部異常處理全局異常處理。

局部異常處理@ExceptionHandler@Controller注解搭配使用,只有指定的controller層出現(xiàn)了異常才會被@ExceptionHandler捕獲到,實際生產(chǎn)中怕是有成百上千個controller了吧,顯然這種方式不合適。

全局異常處理:既然局部異常處理不合適了,自然有人站出來解決問題了,于是就有了@ControllerAdvice這個注解的橫空出世了,@ControllerAdvice搭配@ExceptionHandler徹底解決了全局統(tǒng)一異常處理。當(dāng)然后面還出現(xiàn)了@RestControllerAdvice這個注解,其實就是@ControllerAdvice@ResponseBody結(jié)晶。

Spring Boot的異常如何分類?

Java中的異常就很多,更別說Spring Boot中的異常了,這里不再根據(jù)傳統(tǒng)意義上Java的異常進(jìn)行分類了,而是按照controller進(jìn)行分類,分為進(jìn)入controller前的異常業(yè)務(wù)層的異常,如下圖:

滿屏的try-catch,你不瘆得慌?
進(jìn)入controller之前異常一般是javax.servlet.ServletException類型的異常,因此在全局異常處理的時候需要統(tǒng)一處理。幾個常見的異常如下:

  1. NoHandlerFoundException:客戶端的請求沒有找到對應(yīng)的controller,將會拋出404異常。
  2. HttpRequestMethodNotSupportedException:若匹配到了(匹配結(jié)果是一個列表,不同的是http方法不同,如:Get、Post等),則嘗試將請求的http方法與列表的控制器做匹配,若沒有對應(yīng)http方法的控制器,則拋該異常
  3. HttpMediaTypeNotSupportedException:然后再對請求頭與控制器支持的做比較,比如content-type請求頭,若控制器的參數(shù)簽名包含注解@RequestBody,但是請求的content-type請求頭的值沒有包含application/json,那么會拋該異常(當(dāng)然,不止這種情況會拋這個異常)
  4. MissingPathVariableException:未檢測到路徑參數(shù)。比如url為:/user/{userId},參數(shù)簽名包含@PathVariable("userId"),當(dāng)請求的url為/user,在沒有明確定義url為/user的情況下,會被判定為:缺少路徑參數(shù)

如何統(tǒng)一異常處理?

在統(tǒng)一異常處理之前其實還有許多東西需要優(yōu)化的,比如統(tǒng)一結(jié)果返回的形式。當(dāng)然這里不再細(xì)說了,不屬于本文范疇。

統(tǒng)一異常處理很簡單,這里以前后端分離的項目為例,步驟如下

  1. 新建一個統(tǒng)一異常處理的一個類
  2. 類上標(biāo)注@RestControllerAdvice這一個注解,或者同時標(biāo)注@ControllerAdvice@ResponseBody這兩個注解。
  3. 在方法上標(biāo)注@ExceptionHandler注解,并且指定需要捕獲的異常,可以同時捕獲多個。
下面是作者隨便配置一個demo,如下:

/**
?*?全局統(tǒng)一的異常處理,簡單的配置下,根據(jù)自己的業(yè)務(wù)要求詳細(xì)配置
?*/

@RestControllerAdvice
@Slf4j
public?class?GlobalExceptionHandler?{


????/**
?????*?重復(fù)請求的異常
?????*?@param?ex
?????*?@return
?????*/

????@ExceptionHandler(RepeatSubmitException.class)
????public?ResultResponse?onException(RepeatSubmitException?ex){
????????//打印日志
????????log.error(ex.getMessage());
????????//todo?日志入庫等等操作

????????//統(tǒng)一結(jié)果返回
????????return?new?ResultResponse(ResultCodeEnum.CODE_NOT_REPEAT_SUBMIT);
????}


????/**
?????*?自定義的業(yè)務(wù)上的異常
?????*/

????@ExceptionHandler(ServiceException.class)
????public?ResultResponse?onException(ServiceException?ex){
????????//打印日志
????????log.error(ex.getMessage());
????????//todo?日志入庫等等操作

????????//統(tǒng)一結(jié)果返回
????????return?new?ResultResponse(ResultCodeEnum.CODE_SERVICE_FAIL);
????}


????/**
?????*?捕獲一些進(jìn)入controller之前的異常,有些4xx的狀態(tài)碼統(tǒng)一設(shè)置為200
?????*?@param?ex
?????*?@return
?????*/

????@ExceptionHandler({HttpRequestMethodNotSupportedException.class,
????????????HttpMediaTypeNotSupportedException.class,?HttpMediaTypeNotAcceptableException.class,
????????????MissingPathVariableException.class,?MissingServletRequestParameterException.class,
????????????ServletRequestBindingException.class,?ConversionNotSupportedException.class,
????????????TypeMismatchException.class,?HttpMessageNotReadableException.class,
????????????HttpMessageNotWritableException.class,
????????????MissingServletRequestPartException.class,?BindException.class,
????????????NoHandlerFoundException.class,?AsyncRequestTimeoutException.class})
????public?ResultResponse?onException(Exception?ex){
????????//打印日志
????????log.error(ex.getMessage());
????????//todo?日志入庫等等操作

????????//統(tǒng)一結(jié)果返回
????????return?new?ResultResponse(ResultCodeEnum.CODE_FAIL);
????}
}
注意上面的只是一個例子,實際開發(fā)中還有許多的異常需要捕獲,比如TOKEN失效、過期等等異常,如果整合了其他的框架,還要注意這些框架拋出的異常,比如Shiro,Spring Security等等框架。

異常匹配的順序是什么?

有些朋友可能疑惑了,如果我同時捕獲了父類和子類,那么到底能夠被那個異常處理器捕獲呢?比如ExceptionServiceException。

此時可能就疑惑了,這里先揭曉一下答案,當(dāng)然是ServiceException的異常處理器捕獲了,精確匹配,如果沒有ServiceException的異常處理器才會輪到它的父親父親沒有才會到祖父??傊痪湓挘珳?zhǔn)匹配,找那個關(guān)系最近的。

為什么呢?這可不是憑空瞎說的,源碼為證,出處org.springframework.web.method.annotation.ExceptionHandlerMethodResolver#getMappedMethod,如下:

@Nullable
?private?Method?getMappedMethod(Class?exceptionType)?{
??List>?matches?=?new?ArrayList<>();
????//遍歷異常處理器中定義的異常類型
??for?(Class?mappedException?:?this.mappedMethods.keySet())?{
??????//是否是拋出異常的父類,如果是添加到集合中
???if?(mappedException.isAssignableFrom(exceptionType))?{????
????????//添加到集合中
????matches.add(mappedException);??
???}
??}
????//如果集合不為空,則按照規(guī)則進(jìn)行排序
??if?(!matches.isEmpty())?{
???matches.sort(new?ExceptionDepthComparator(exceptionType));
??????//取第一個
???return?this.mappedMethods.get(matches.get(0));
??}
??else?{
???return?null;
??}
?}
在初次異常處理的時候會執(zhí)行上述的代碼找到最匹配的那個異常處理器方法,后續(xù)都是直接從緩存中(一個Map結(jié)構(gòu),key是異常類型,value是異常處理器方法)。

別著急,上面代碼最精華的地方就是對matches進(jìn)行排序的代碼了,我們來看看ExceptionDepthComparator這個比較器的關(guān)鍵代碼,如下:

//遞歸調(diào)用,獲取深度,depth值越小越精準(zhǔn)匹配
private?int?getDepth(Class?declaredException,?Class?exceptionToMatch,?int?depth)?{
????//如果匹配了,返回
??if?(exceptionToMatch.equals(declaredException))?{
???//?Found?it!
???return?depth;
??}
??//?遞歸結(jié)束的條件,最大限度了
??if?(exceptionToMatch?==?Throwable.class)?{
???return?Integer.MAX_VALUE;
??}
????//繼續(xù)匹配父類
??return?getDepth(declaredException,?exceptionToMatch.getSuperclass(),?depth? ?1);
?}
精髓全在這里了,一個遞歸搞定,計算深度,depth初始值為0。值越小,匹配度越高越精準(zhǔn)。

總結(jié)

全局異常的文章萬萬千,能夠講清楚的能有幾篇呢?只出最精的文章,做最野的程序員,如果覺得不錯的,關(guān)注分享走一波,謝謝支持?。?!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗。要解決這一問題,需從設(shè)計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉