Spring Web MVC 採用經典的 前端控制器模式,DispatcherServlet 作為唯一入口,協調 HandlerMapping、HandlerAdapter、HandlerExceptionResolver、ViewResolver 等核心組件完成請求分發、執行、異常處理、視圖渲染全流程。
initFrameworkServlet() 按依賴順序初始化:
protected void initFrameworkServlet() {
initMultipartResolver(); // 1. 文件上傳解析
initLocaleResolver(); // 2. 國際化解析
initThemeResolver(); // 3. 主題解析
initHandlerMappings(); // 4. 處理器映射【核心】
initHandlerAdapters(); // 5. 處理器適配器【核心】
initHandlerExceptionResolvers(); // 6. 異常解析器
initRequestToViewNameTranslator(); // 7. 請求到視圖名轉換
initViewResolvers(); // 8. 視圖解析器【核心】
}
每個 initXxx() 均採用 「上下文查找 → 排序 → 緩存 → 無則用默認策略」 模式,體現了 Spring「約定優於配置」的設計哲學。
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
返回 HandlerExecutionChain,封裝 handler(Controller/HandlerMethod)+ interceptors[]。
urlMap,調用 registerHandler(url, handler) 存入 handlerMap (HashMap)。支援 Bean 名稱懶加載與默認處理器 /*。handlerMap.get(lookupPath)。AntPathMatcher 匹配,選最長路徑優先(bestPathMatch.length() <= registeredPath.length())。protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) { noHandlerFound(...); return; }
// 1. 攔截器預處理(正序)
for (HandlerInterceptor interceptor : mappedHandler.getInterceptors()) {
if (!interceptor.preHandle(request, response, handler)) {
triggerAfterCompletion(...); return;
}
}
// 2. HandlerAdapter 執行業務邏輯
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
// 3. 攔截器後處理(逆序)
for (int i = interceptors.length - 1; i >= 0; i--) {
interceptors[i].postHandle(request, response, handler, mv);
}
// 4. 視圖渲染
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
}
SimpleControllerHandlerAdapter 適配 Controller 接口,RequestMappingHandlerAdapter 適配 @RequestMapping 方法,新協議只需新增 Adapter,DispatcherServlet 零修改。preHandle 正序、postHandle 逆序、afterCompletion 逆序(保證資源釋放順序正確)。protected View resolveViewName(String viewName, Locale locale) {
for (ViewResolver vr : viewResolvers) {
View view = vr.resolveViewName(viewName, locale);
if (view != null) return view; // 首個非空即返回
}
return null;
}
支援多 ViewResolver 鏈,順序由 order 屬性決定。
render() → 合併靜態屬性 + 動態模型 → mergedModel。exposeModelAsRequestAttributes():將模型數據 request.setAttribute(),JSP/Thymeleaf 可直接取用。exposeHelpers():JSTL 區域化上下文等輔助對象。prepareForRendering() → getUrl()(由 UrlBasedViewResolver 構建:prefix + viewName + suffix)。RequestDispatcher.forward() 轉發到目標資源(JSP/模板文件)。如 AbstractExcelView、AbstractPdfView、MappingJackson2JsonView 繼承 AbstractView,重寫 renderMergedOutputModel() 直接寫 HttpServletResponse.getOutputStream(),無需轉發。
Client Request
↓
DispatcherServlet.doService()
↓
DispatcherServlet.doDispatch()
↓
HandlerMapping.getHandler() → HandlerExecutionChain(handler + interceptors)
↓
Interceptor.preHandle() [正序]
↓
HandlerAdapter.handle() → ModelAndView
↓
Interceptor.postHandle() [逆序]
↓
ViewResolver.resolveViewName() → View
↓
View.render() → exposeModel → forward / write response
↓
Interceptor.afterCompletion() [逆序]
↓
Client Response
| 擴展點 | 接口/抽象類 | 典型應用場景 |
|---|---|---|
| 請求映射 | HandlerMapping | RESTful URL、版本號路由、動態權限映射 |
| Handler 執行 | HandlerAdapter | 自定義參數綁定、返回值處理、異步處理 |
| 攔截邏輯 | HandlerInterceptor | 日誌、權限、限流、鏈路追蹤 |
| 異常處理 | HandlerExceptionResolver | 統一錯誤碼、友好錯誤頁、API 異常封裝 |
| 視圖解析 | ViewResolver | 多視圖技術共存、內容協商 |
| 視圖渲染 | View | PDF/Excel/報表生成、自定義模板引擎 |
Spring MVC 的優雅在於:將 Web 層的各種變化點(映射策略、執行協議、視圖技術、異常處理)全部抽象為可插拔的 Strategy 接口,DispatcherServlet 作為不變的協調者串聯起所有策略。這不僅實現了高度解耦,更為框架演進(如 WebFlux 的異步非阻塞模型)預留了架構空間。深入理解這套機制,能讓你在遇到「請求進不了 Controller」、「視圖解析失敗」、「攔截器不生效」等疑難雜症時,精準定位到具備組件與生命週期節點。