SpringBoot一個請求的處理全過程分享
平時只是在用SpringBoot框架,但并沒有詳細(xì)研究過請求執(zhí)行的一個具體過程,所以本文主要來梳理一下SpringBoot請求處理的全過程。
請求處理流程圖
容器包含關(guān)系圖

請求簡要流程圖

請求詳細(xì)流程圖

請求處理流程詳解
請求處理主要流程
- 過濾器鏈chain.doFilter之前的執(zhí)行(過濾器是在Server容器中的,如Tomcat);
- 攔截器鏈preHandle方法執(zhí)行;
- 路徑映射、參數(shù)綁定(參數(shù)解析、參數(shù)轉(zhuǎn)換、參數(shù)校驗(yàn));
- Controller的具體方法執(zhí)行;
- 返回值處理(含信息轉(zhuǎn)換);
- 攔截器鏈postHandle方法執(zhí)行;
- 異常解析器處理異常(@ControllerAdvice、自定義異常解析器都在這里執(zhí)行);
- 視圖解析渲染;
- 攔截器鏈afterCompletion方法執(zhí)行;
- 過濾器鏈chain.doFilter之后的執(zhí)行。
請求處理詳細(xì)流程
Tomcat線程接受到請求,經(jīng)過一系列調(diào)用后,調(diào)用到ApplicationFilterChain的doFilter方法。doFilter方法調(diào)用ApplicationFilterChain的internalDoFilter方法,依次執(zhí)行過濾器鏈的每個Filter的doFilter。
過濾器鏈的所有doFIlter執(zhí)行完畢, 控制權(quán)交回ApplicationFilterChain, 經(jīng)過一系列調(diào)用后,調(diào)用到DispatcherServlet的doDispatch方法。
doDispatch方法的主要流程:
- DispatcherServlet的getHandler方法:得到處理執(zhí)行器鏈(包含處理器和攔截器鏈)。
- DispatcherServlet的getHandlerAdapter方法:得到處理器適配器。
- HandlerExecutionChain的applyPreHandle方法:執(zhí)行執(zhí)行器鏈中的所有攔截器方法preHandle。
AbstractHandlerMethodAdapter的handle方法:該方法主要包含路徑映射、參數(shù)bangd (參數(shù)解析、參數(shù)轉(zhuǎn)換、參數(shù)校驗(yàn))、調(diào)用具體控制器方法、返回值處理(含信息轉(zhuǎn)換)等操作。
handle方法的主要流程:
- 調(diào)用RequestMappingHandlerAdapter的handleInternal方法
- handleInternal方法又調(diào)用RequestMappingHandlerAdapter的invokeHandlerMethod方法
invokeHandlerMethod方法的主要流程:
- 調(diào)用RequestMappingHandlerAdapter的createInvocableHandlerMethod方法:注冊參數(shù)解析器、返回值處理器、信息轉(zhuǎn)化器等到ServletInvocableHandlerMethod 對象實(shí)例中。
- 調(diào)用ServletInvocableHandlerMethod的invokeAndHandle方法。
invokeAndHandle方法的主要流程:
- 調(diào)用InvocableHandlerMethod的invokeForRequest方法
- invokeForRequest方法又調(diào)用InvocableHandlerMethod的doInvoke方法
doInvoke方法的主要流程:
- 調(diào)用InvocableHandlerMethod的getMethodArgumentValues方法:路徑映射、參數(shù)綁定(參數(shù)解析、參數(shù)轉(zhuǎn)換、參數(shù)校驗(yàn))。
- 調(diào)用Method的invoke方法,內(nèi)部調(diào)用DelegatingMethodAccessorImpl的invoke方法,內(nèi)部調(diào)用InvocableHandlerMethod的doInvoke方法,內(nèi)部調(diào)用NativeMethodAccessorImpl的invoke方法,內(nèi)部調(diào)用NativeMethodAccessorImpl的invoke0方法,內(nèi)部調(diào)用具體Controller的具體方法,得到響應(yīng)結(jié)果。
- 調(diào)用HandlerMethodReturnValueHandlerComposite的handleReturnValue方法:返回值處理(含信息轉(zhuǎn)換)。
- 調(diào)用HandlerExecutionChain的applyPostHandle方法:執(zhí)行執(zhí)行器鏈中的所有攔截方法postHandle。
- 調(diào)用DispatcherServlet的processDispatchResult方法。
processDispatchResult方法的主要流程:
- 調(diào)用DispatcherServlet的processHandlerException方法:異常處理(獲取合適的異常解析器處理異常信息,@ControllerAdvice全局異常處理和自定義異常解析器都是在這一步執(zhí)行的)。
- 調(diào)用DispatcherServlet的render方法:視圖解析渲染。
- 調(diào)用HandlerExecutionChain的triggerAfterCompletion方法:執(zhí)行執(zhí)行器鏈中的所有攔截方法afterCompletion。
- 控制權(quán)交回ApplicationFilterChain , 繼續(xù)執(zhí)行過濾器鏈的所有doFIlter之后的代碼。
常見問題
全局異常處理失效
1.@ControllerAdvice作用范圍
攔截器的preHandle方法、postHandle方法拋出的異常在ControllerAdvice處理范圍內(nèi),但攔截器的afterCompletion方法拋出的異常不在處理范圍內(nèi)(攔截器的afterCompletion拋出的異常會被直接catch處理,不會往外拋出異常,只會打印錯誤日志)。
HandlerExecutionChain類源碼
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}過濾器拋出的異常不在ControllerAdvice處理范圍內(nèi)。要處理過濾器拋出的異常,可以自定義Filter并放在過濾鏈的最前面,catch處理異常。
2.多個@ControllerAdvice優(yōu)先級問題
- 多個使用@ControllerAdvice 的Bean按執(zhí)行順序(通過Order注解設(shè)置執(zhí)行順序,值越小月優(yōu)先執(zhí)行)依次執(zhí)行
- 當(dāng)某個Bean的方法匹配上異常時,進(jìn)行異常處理,直接返回,后續(xù)的方法和Bean不在執(zhí)行。
關(guān)于全局異常處理詳細(xì)講解可參考文章:[SpringBoot全局異常處理]
后續(xù)文章會繼續(xù)針對請求流程里面的一些主要功能作深入探討,如:過濾器、攔截器、參數(shù)解析、參數(shù)轉(zhuǎn)換、參數(shù)校驗(yàn)、返回值處理、異常處理等方面。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解eclipse項(xiàng)目中的.classpath文件原理
這篇文章介紹了eclipse項(xiàng)目中的.classpath文件的原理,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
作為Java程序員應(yīng)該掌握的10項(xiàng)技能
這篇文章主要介紹了作為Java程序員應(yīng)該掌握的10項(xiàng)技能,包括java的知識點(diǎn)與相關(guān)的技能,對于java的學(xué)習(xí)有不錯的參考借鑒價值,需要的朋友可以參考下2015-05-05
JSONArray在Java中的應(yīng)用操作實(shí)例
JSONArray是org.json庫用于處理JSON數(shù)組的類,可將Java對象(Map/List)轉(zhuǎn)換為JSON格式,提供增刪改查等操作,適用于前后端數(shù)據(jù)交互,并涵蓋安全、性能優(yōu)化及最佳實(shí)踐,本文給大家介紹JSONArray在Java中的應(yīng)用,感興趣的朋友一起看看吧2025-07-07
從0開始學(xué)習(xí)大數(shù)據(jù)之java spark編程入門與項(xiàng)目實(shí)踐
這篇文章主要介紹了從0開始學(xué)習(xí)大數(shù)據(jù)之java spark編程入門與項(xiàng)目實(shí)踐,結(jié)合具體入門項(xiàng)目分析了大數(shù)據(jù)java spark編程項(xiàng)目建立、調(diào)試、輸出等相關(guān)步驟及操作技巧,需要的朋友可以參考下2019-11-11
Spring?Boot?整合?SSE(Server-Sent?Events)實(shí)戰(zhàn)案例(全網(wǎng)最全)
本文通過實(shí)戰(zhàn)案例講解SpringBoot整合SSE技術(shù),涵蓋實(shí)現(xiàn)原理、代碼配置、異常處理及前端交互,討論與WebSocket對比、分布式解決方案、性能監(jiān)控,感興趣的朋友跟隨小編一起看看吧2025-08-08
SpringBoot 單元測試實(shí)戰(zhàn)(Mockito,MockBean)
這篇文章主要介紹了SpringBoot 單元測試實(shí)戰(zhàn)(Mockito,MockBean),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Spring Security組件一鍵接入驗(yàn)證碼登錄和小程序登錄的詳細(xì)過程
這篇文章主要介紹了Spring Security 一鍵接入驗(yàn)證碼登錄和小程序登錄,簡單介紹一下這個插件包的相關(guān)知識,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-04-04
Spring?Boot實(shí)現(xiàn)MyBatis動態(tài)創(chuàng)建表的操作語句
這篇文章主要介紹了Spring?Boot實(shí)現(xiàn)MyBatis動態(tài)創(chuàng)建表,MyBatis提供了動態(tài)SQL,我們可以通過動態(tài)SQL,傳入表名等信息然組裝成建表和操作語句,本文通過案例講解展示我們的設(shè)計(jì)思路,需要的朋友可以參考下2024-01-01
Java基于線程實(shí)現(xiàn)帶有滾動效果的Label標(biāo)簽實(shí)例
這篇文章主要介紹了Java基于線程實(shí)現(xiàn)帶有滾動效果的Label標(biāo)簽,實(shí)例分析了java線程的使用技巧及l(fā)abel標(biāo)簽的實(shí)現(xiàn)方法,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07

