Spring Boot異常處理try-catch應(yīng)該怎么使用?
1. 為什么異常值得單獨寫一整個系列
在多數(shù)業(yè)務(wù)代碼中,異常往往被當(dāng)作一種“不得不寫的語法”:
try {
service.process();
} catch (Exception e) {
log.error("error", e);
}
但在真實的 Web 系統(tǒng)中,異常從來不是一個語法問題,而是一個系統(tǒng)失控時的兜底機制。
一次 HTTP 請求,往往會經(jīng)歷如下鏈路:
- Filter
- Interceptor
- Controller
- 參數(shù)綁定與校驗
- Service
- DAO
- 事務(wù)
- AOP 代理
- JSON 序列化
異??梢栽谌魏我粋€環(huán)節(jié)出現(xiàn),而且一旦出現(xiàn),就會“逆著調(diào)用棧”向上冒泡,最終由框架決定:
- 是否回滾事務(wù)
- 是否返回 500
- 返回什么格式
- 是否記錄堆棧
- 是否暴露錯誤信息給前端
因此,異常不是“邊角料”,而是整個調(diào)用鏈的終點匯合處。
2. Java 異常模型的關(guān)鍵認知(只講對后面有用的)
2.1 Throwable 體系結(jié)構(gòu)
Throwable
├── Error
└── Exception
├── RuntimeException
└── Checked Exception
- Error:JVM 級錯誤,應(yīng)用通常無能為力
- Exception:應(yīng)用級異常
- RuntimeException:Spring 默認認為這是“不可恢復(fù)異常”
- Checked Exception:需要顯式聲明和處理
Spring 事務(wù)為什么默認只對 RuntimeException 回滾?
這個問題在后面的事務(wù)異常章節(jié)會專門展開。
2.2 異常傳播是“反向調(diào)用鏈”
正常調(diào)用是:
Controller → Service → DAO
異常傳播是:
DAO 拋異常 → Service → Controller → 框架
誰最后接住異常,誰就擁有最終解釋權(quán)。
3. 為什么 Web 系統(tǒng)不能到處 try-catch
3.1 try-catch 的三個常見問題
- 吞異常,導(dǎo)致問題被掩蓋
- 重復(fù)代碼,Controller 層異常處理泛濫
- 破壞事務(wù)回滾邏輯
例如:
@Transactional
public void createOrder() {
try {
saveOrder();
} catch (Exception e) {
log.error("error", e);
}
}
這個代碼看起來穩(wěn)健,實際上事務(wù)已經(jīng)無法回滾。
3.2 異常必須“集中處理”
在 Web 架構(gòu)中,有一個非常重要的設(shè)計原則:
異常應(yīng)該在“邊界層”統(tǒng)一處理,而不是在業(yè)務(wù)層消化。
Spring MVC 正是基于這個原則,設(shè)計了一整套異常處理機制。
4. Spring MVC 的異常處理總體設(shè)計思想
4.1 正常流程 vs 異常流程
正常流程:
請求 → Handler → 返回值 → 響應(yīng)
異常流程:
請求 → Handler → 拋異常 → 異常解析 → 響應(yīng)
Spring MVC 的核心設(shè)計點在于:
異常不是 if-else 分支,而是一條獨立的處理鏈路。
4.2 異常處理在 DispatcherServlet 中的位置
DispatcherServlet 是整個 MVC 的“總控中樞”。
在其核心方法 doDispatch 中,異常被統(tǒng)一捕獲:
try {
// 查找 Handler 并執(zhí)行
} catch (Exception ex) {
dispatchException = ex;
}
這意味著:
- Controller 不需要感知異常如何返回
- 框架會統(tǒng)一接管異常
5. Spring MVC 的三種基礎(chǔ)異常處理方式
5.1 直接拋出異常(推薦)
@GetMapping("/order")
public Order getOrder() {
throw new IllegalArgumentException("參數(shù)錯誤");
}
異常會交給框架處理,而不是在 Controller 內(nèi)部解決。
5.2 @ExceptionHandler:局部異常處理
@RestController
public class OrderController {
@ExceptionHandler(IllegalArgumentException.class)
public String handleIllegalArg(Exception e) {
return e.getMessage();
}
}
特點:
- 只對當(dāng)前 Controller 生效
- 適合非常局部的異常場景
5.3 @ControllerAdvice:全局異常處理(重點)
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ErrorResponse handle(Exception e) {
return new ErrorResponse("500", e.getMessage());
}
}
這是 Spring Boot 項目中最常見的異常處理入口。
6. @ControllerAdvice 的設(shè)計價值
6.1 為什么它是“全局異常處理”的核心
@ControllerAdvice 本質(zhì)上解決了三個問題:
- 異常集中管理
- 返回格式統(tǒng)一
- 與業(yè)務(wù)邏輯解耦
6.2 多個 ControllerAdvice 的順序問題
Spring 支持定義多個全局異常處理器:
@Order(1)
@RestControllerAdvice
class BizExceptionHandler {}
@Order(2)
@RestControllerAdvice
class SystemExceptionHandler {}
優(yōu)先級越小,越先執(zhí)行。
7. 異常處理的第一版架構(gòu)形態(tài)
在“入門階段”,一個相對合理的異常架構(gòu)通常是:
Controller ↓ 拋異常 ↓ @ControllerAdvice ↓ 統(tǒng)一錯誤響應(yīng)
對應(yīng)的返回結(jié)構(gòu)示例:
{
"code": "SYSTEM_ERROR",
"message": "系統(tǒng)異常,請稍后再試"
}
8. 異常處理流程圖(概覽)
圖1 Spring MVC 異常處理基本流程圖
9. 本篇小結(jié)(從入門視角看異常)
到這里,我們只做了三件事:
- 糾正“異常只是 try-catch”的認知
- 明確異常是 Web 系統(tǒng)的統(tǒng)一出口
- 理解 Spring MVC 為什么要集中處理異常
但我們還沒有回答幾個關(guān)鍵問題:
- 異常是如何一步步被解析的?
- 為什么 @ExceptionHandler 能生效?
- Spring Boot 的 /error 是干什么的?
- 為什么有些異常進不了 ControllerAdvice?
?? 這些問題,都需要進入源碼層面才能解釋清楚。
到此這篇關(guān)于Spring Boot異常處理try-catch應(yīng)該怎么使用?的文章就介紹到這了,更多相關(guān)Spring Boot異常處理try-catch內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
參考資料
- Spring Framework Reference – Exception Handling
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-exceptionhandler.html - Spring MVC 源碼(DispatcherServlet)
https://github.com/spring-projects/spring-framework
相關(guān)文章
使用mybatis的@Interceptor實現(xiàn)攔截sql的方法詳解
攔截器是一種基于 AOP(面向切面編程)的技術(shù),它可以在目標對象的方法執(zhí)行前后插入自定義的邏輯,本文給大家介紹了使用mybatis的@Interceptor實現(xiàn)攔截sql的方法,需要的朋友可以參考下2024-03-03
SpringBoot中實現(xiàn)數(shù)據(jù)脫敏處理的方法詳解
項目開發(fā)中,在處理敏感信息時,數(shù)據(jù)脫敏是一項重要的安全措施,本文主要為大家介紹了如何在SpringBoot項目中進行數(shù)據(jù)脫敏處理,有需要的可以了解下2025-03-03
MyBatis 執(zhí)行動態(tài) SQL語句詳解
大家對mybatis執(zhí)行任意sql語句都了解,那么MyBatis執(zhí)行動態(tài)SQL語句呢?下面腳本之家小編給大家解答下mybatis執(zhí)行動態(tài)sql語句的方法,非常不錯,感興趣的朋友參考下吧2016-08-08
tk.mybatis通用插件updateByPrimaryKeySelective無法自動更新列的解決辦法
tk.mybatis是一個很好用的通用插件,本文主要介紹了tk.mybatis通用插件updateByPrimaryKeySelective無法自動更新列的解決辦法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12
Spring Cloud 如何保證微服務(wù)內(nèi)安全
這篇文章主要介紹了Spring Cloud 如何保證微服務(wù)內(nèi)安全的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

