最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot 全局異常處理策略設(shè)計(jì)之@ExceptionHandler 與 @ControllerAdvice 生效原理源碼解析

 更新時(shí)間:2026年01月09日 09:48:02   作者:Qiuner  
SpringBoot全局異常處理策略設(shè)計(jì)@ExceptionHandler與@ControllerAdvice生效原理源碼解析,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

Spring Boot 全局異常處理策略設(shè)計(jì)(三):@ExceptionHandler 與 @ControllerAdvice 生效原理源碼解析

1. 從一個(gè)常見疑問說起

很多人在使用全局異常處理時(shí),都會(huì)遇到類似問題:

  • 為什么這個(gè)異常沒進(jìn)我的 @ControllerAdvice?
  • 多個(gè) @ExceptionHandler 時(shí),哪個(gè)先生效?
  • 參數(shù)、返回值為什么能自動(dòng)解析?
  • 為什么同一個(gè)異常,在不同 Controller 表現(xiàn)不一樣?

這些問題,用“注解怎么寫”是回答不了的,只能從源碼解釋

2. ExceptionHandlerExceptionResolver 是誰在干活

在上一篇中我們已經(jīng)知道,異常最終會(huì)進(jìn)入這條責(zé)任鏈:

ExceptionHandlerExceptionResolver
→ ResponseStatusExceptionResolver
→ DefaultHandlerExceptionResolver

@ExceptionHandler 和 @ControllerAdvice 的真正執(zhí)行者,就是:

ExceptionHandlerExceptionResolver

3. ExceptionHandlerExceptionResolver 的核心職責(zé)

從類注釋就能看出它的定位:

/**
 * An {@link HandlerExceptionResolver} that resolves exceptions through
 * {@link ExceptionHandler} methods.
 */

它只做一件事:

找到能處理當(dāng)前異常的 @ExceptionHandler 方法,并執(zhí)行它

4. @ExceptionHandler 方法是如何被掃描的

4.1 初始化階段:掃描所有異常處理方法

在容器啟動(dòng)階段,ExceptionHandlerExceptionResolver 會(huì)執(zhí)行初始化邏輯:

public void afterPropertiesSet() {
    initExceptionHandlerAdviceCache();
}

4.2 掃描 @ControllerAdvice

private void initExceptionHandlerAdviceCache() {
    List<ControllerAdviceBean> adviceBeans =
        ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
}

關(guān)鍵點(diǎn):

  • 掃描整個(gè) Spring 容器
  • 找出所有標(biāo)注了 @ControllerAdvice 的 Bean
  • 封裝為 ControllerAdviceBean

4.3 ControllerAdvice 的“作用范圍”不是全局那么簡(jiǎn)單

@ControllerAdvice 支持條件匹配:

@ControllerAdvice(
    basePackages = "com.example.web",
    annotations = RestController.class
)

源碼中通過 HandlerTypePredicate 判斷是否適用當(dāng)前 Controller。

?? 這也是為什么:

有些 Advice 明明存在,卻對(duì)某些 Controller 不生效

5. @ExceptionHandler 方法是如何被緩存的

5.1 ExceptionHandlerMethodResolver

每一個(gè) Controller 或 Advice,都會(huì)對(duì)應(yīng)一個(gè)解析器:

new ExceptionHandlerMethodResolver(beanType);

它會(huì):

  • 掃描所有方法
  • 找出 @ExceptionHandler
  • 建立異常類型 → 方法的映射關(guān)系

5.2 一個(gè)方法可以處理多個(gè)異常

@ExceptionHandler({IllegalArgumentException.class, NullPointerException.class})
public ErrorResponse handle(Exception e) {}

源碼中會(huì)把它拆解成多條映射關(guān)系。

5.3 異常匹配是“最近優(yōu)先”

如果存在繼承關(guān)系:

RuntimeException
└── IllegalArgumentException

IllegalArgumentException 會(huì)優(yōu)先匹配,而不是父類異常。

這是通過 ExceptionDepthComparator 實(shí)現(xiàn)的。

6. 異常發(fā)生時(shí),Resolver 是如何找方法的

異常真正發(fā)生后,會(huì)進(jìn)入:

protected ModelAndView doResolveHandlerMethodException(...)

核心邏輯:

  1. 先找 Controller 內(nèi)部的 @ExceptionHandler
  2. 再找全局 @ControllerAdvice
  3. 找到就執(zhí)行,找不到返回 null

6.1 Controller 內(nèi)部?jī)?yōu)先于 ControllerAdvice

這是一個(gè)非常重要的優(yōu)先級(jí)規(guī)則:

局部異常處理 > 全局異常處理

源碼中體現(xiàn)為:

getExceptionHandlerMethod(handlerMethod, exception)

先基于當(dāng)前 Controller 查找。

7. @ExceptionHandler 方法是如何被執(zhí)行的

一旦找到目標(biāo)方法,Spring 會(huì)把它包裝成:

ServletInvocableHandlerMethod

這個(gè)類你在 MVC 參數(shù)解析中已經(jīng)見過。

7.1 參數(shù)是如何自動(dòng)注入的

@ExceptionHandler(Exception.class)
public ErrorResponse handle(
    Exception ex,
    HttpServletRequest request
) {}

參數(shù)解析復(fù)用的正是:

  • HandlerMethodArgumentResolver 體系

?? 異常處理方法,本質(zhì)上也是一個(gè) MVC 方法。

7.2 返回值是如何寫入響應(yīng)的

返回值處理同樣復(fù)用:

  • HandlerMethodReturnValueHandler
  • HttpMessageConverter

所以你可以:

  • 返回對(duì)象
  • 返回 ResponseEntity
  • 返回 void

8. 為什么 @ResponseBody 能生效

在 Spring Boot 中,常見寫法是:

@RestControllerAdvice

它本質(zhì)等價(jià)于:

@ControllerAdvice
@ResponseBody

@ResponseBody 的解析發(fā)生在:

  • 返回值處理階段
  • 由 RequestResponseBodyMethodProcessor 完成

9. 多個(gè) @ControllerAdvice 的執(zhí)行順序

9.1 順序規(guī)則

優(yōu)先級(jí)由以下規(guī)則決定:

  1. @Order
  2. Ordered 接口
  3. 默認(rèn)順序(最低優(yōu)先級(jí))
@Order(1)
@RestControllerAdvice
class BizExceptionAdvice {}
@Order(2)
@RestControllerAdvice
class SystemExceptionAdvice {}

9.2 為什么順序很重要

因?yàn)椋?/p>

  • 第一個(gè)匹配成功的異常處理方法會(huì)直接返回
  • 后續(xù) Advice 不再執(zhí)行

10. 常見“異常不生效”的根本原因

現(xiàn)象根本原因
Advice 不生效basePackages 不匹配
方法不進(jìn)異常類型不匹配
被吞掉前面 Resolver 已處理
返回 500Resolver 返回 null

這些問題,只有看源碼才能徹底理解。

11. 異常處理方法執(zhí)行流程圖

圖1 @ExceptionHandler 方法解析與執(zhí)行流程

12. 本篇關(guān)鍵認(rèn)知升級(jí)

到這里,你應(yīng)該已經(jīng)清楚:

  1. @ExceptionHandler 并不是“魔法”
  2. ControllerAdvice 不是“全局兜底”,而是有嚴(yán)格匹配規(guī)則
  3. 異常處理方法本質(zhì)上是一個(gè) MVC Handler
  4. Resolver 鏈決定了異常的最終命運(yùn)

13. 下一篇預(yù)告

到目前為止,我們講的還是 Spring MVC 層面的異常。
但在 Spring Boot 中,還有一個(gè)繞不開的存在:

/error

  • 它什么時(shí)候被觸發(fā)?
  • 為什么有的異常進(jìn)了 /error,而不是 ControllerAdvice?
  • ErrorController、ErrorAttributes 是干什么的?

?? 下一篇,我們正式進(jìn)入 Spring Boot 的異常“二次封裝世界”。

參考資料

  • Spring Framework Reference – Exception Handling
    https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-exceptionhandler.html
  • ExceptionHandlerExceptionResolver 源碼
    https://github.com/spring-projects/spring-framework

到此這篇關(guān)于Spring Boot 全局異常處理策略設(shè)計(jì)之@ExceptionHandler 與 @ControllerAdvice 生效原理源碼解析的文章就介紹到這了,更多相關(guān)Spring Boot 全局異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis之動(dòng)態(tài)SQL和緩存使用及說明

    MyBatis之動(dòng)態(tài)SQL和緩存使用及說明

    這篇文章主要介紹了MyBatis之動(dòng)態(tài)SQL和緩存使用及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2026-05-05
  • 解決idea打包成功但是resource下的文件沒有成功的問題

    解決idea打包成功但是resource下的文件沒有成功的問題

    這篇文章主要介紹了解決idea打包成功但是resource下的文件沒有成功的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • 詳解Java關(guān)于JDK中時(shí)間日期的API

    詳解Java關(guān)于JDK中時(shí)間日期的API

    這篇文章主要介紹了詳解Java關(guān)于JDK中時(shí)間日期的API,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • SpringBoot中@ComponentScan注解過濾排除不加載某個(gè)類的3種方法

    SpringBoot中@ComponentScan注解過濾排除不加載某個(gè)類的3種方法

    這篇文章主要給大家介紹了關(guān)于SpringBoot中@ComponentScan注解過濾排除不加載某個(gè)類的3種方法,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用SpringBoot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 基于hashmap 的擴(kuò)容和樹形化全面分析

    基于hashmap 的擴(kuò)容和樹形化全面分析

    這篇文章主要介紹了hashmap 的擴(kuò)容和樹形化的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • LogBack+MybatisPlus實(shí)現(xiàn)打印sql日志

    LogBack+MybatisPlus實(shí)現(xiàn)打印sql日志

    本文主要介紹了LogBack+MybatisPlus實(shí)現(xiàn)打印sql日志,設(shè)置異步appender實(shí)現(xiàn)按天滾動(dòng)切割日志,保留3天歷史并自動(dòng)清理,替代P6Spy避免日志過大,同時(shí)需配置MybatisPlus日志輸出路徑,并區(qū)分MyBatis與MyBatisPlus日志輸出
    2025-09-09
  • 教你怎么用Java數(shù)組和鏈表實(shí)現(xiàn)棧

    教你怎么用Java數(shù)組和鏈表實(shí)現(xiàn)棧

    本篇文章為大家詳細(xì)介紹了怎么用Java數(shù)組和鏈表實(shí)現(xiàn)棧,文中有非常詳細(xì)的代碼示例及注釋,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • 詳解5種Java中常見限流算法

    詳解5種Java中常見限流算法

    在高并發(fā)系統(tǒng)中,出于系統(tǒng)保護(hù)角度考慮,通常會(huì)對(duì)流量進(jìn)行限流;不但在工作中要頻繁使用,而且也是面試中的高頻考點(diǎn)。本文就為大家整理了5種Java中常見限流算法,需要的可以參考一下
    2023-04-04
  • java的NIO管道用法代碼分享

    java的NIO管道用法代碼分享

    這篇文章主要介紹了java的NIO管道用法代碼分享,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • Springboot發(fā)送post請(qǐng)求的幾種方式總結(jié)

    Springboot發(fā)送post請(qǐng)求的幾種方式總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Springboot發(fā)送post請(qǐng)求的幾種方式,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴可以了解一下
    2024-01-01

最新評(píng)論

策勒县| 贵州省| 东平县| 承德县| 宁津县| 台南县| 三河市| 海宁市| 陆良县| 稷山县| 江孜县| 武邑县| 织金县| 天气| 嵊州市| 青浦区| 苏州市| 大安市| 陈巴尔虎旗| 芷江| 武乡县| 衢州市| 朔州市| 会宁县| 遵化市| 白城市| 余庆县| 西华县| 沙湾县| 莱西市| 扎赉特旗| 大田县| 宣城市| 台南市| 新野县| 太原市| 梅州市| 绥滨县| 当雄县| 长沙县| 沾益县|