在 Spring MVC 中,請求從客戶端發送到服務器后,需要經過一系列組件的處理才能最終到達具體的 Controller 方法。這個過程涉及多個核心組件和復雜的映射機制,下面詳細解析其工作流程:
1. 核心組件與請求流程
Spring MVC 的請求處理流程主要涉及以下核心組件:
DispatcherServlet:前端控制器,接收所有 HTTP 請求,是整個請求處理的入口。
HandlerMapping:請求映射處理器,負責將請求 URL 映射到對應的 Handler(即 Controller 方法)。
HandlerAdapter:處理器適配器,將不同類型的 Handler 統一為可執行的接口。
Controller:具體的業務控制器,處理請求并返回 ModelAndView。
ViewResolver:視圖解析器,將邏輯視圖名解析為具體的 View 對象。
View:視圖對象,負責將模型數據渲染到客戶端。
請求處理流程:
客戶端請求 → DispatcherServlet → HandlerMapping → HandlerAdapter →Controller → ModelAndView → ViewResolver → View → 響應客戶端
2. HandlerMapping 的請求映射機制
HandlerMapping 是實現 URL 到 Controller 方法映射的核心組件,Spring MVC 提供了多種實現:
RequestMappingHandlerMapping:處理 @RequestMapping
注解的映射(最常用)。
BeanNameUrlHandlerMapping:根據 Bean 名稱映射請求(如 /hello
→ helloController
Bean)。
SimpleUrlHandlerMapping:通過配置文件手動指定 URL 與 Handler 的映射關系。
基于注解的映射流程
當使用 @RequestMapping
或其派生注解(如 @GetMapping
)時:
啟動時掃描:Spring MVC 在啟動時會掃描所有帶有 @Controller
或 @RestController
注解的 Bean。
解析方法映射:提取這些 Bean 中所有標注了 @RequestMapping
的方法,構建映射關系。
生成 HandlerMethod 對象:將每個映射方法封裝為 HandlerMethod
對象,包含控制器實例、方法反射信息和請求匹配條件(如 URL、請求方法、請求參數等)。
注冊到映射器:將 HandlerMethod
對象注冊到 RequestMappingHandlerMapping
的內部映射表中。
3. DispatcherServlet 的請求分發
當接收到請求時,DispatcherServlet
會按以下步驟處理:
獲取 HandlerExecutionChain:
HandlerExecutionChain handler = getHandler(request);
DispatcherServlet 調用 HandlerMapping
的 getHandler(request)
方法,根據請求 URL 查找匹配的 Handler。
HandlerMapping 返回一個 HandlerExecutionChain
對象,包含 Handler(即 Controller 方法)和相關的攔截器(Interceptor)。
獲取 HandlerAdapter:
HandlerAdapter ha = getHandlerAdapter(handler.getHandler());
DispatcherServlet 根據 Handler 的類型,從已注冊的 HandlerAdapter
中選擇合適的適配器。
例如,RequestMappingHandlerAdapter
用于處理基于注解的 Controller 方法。
執行 Handler:
ModelAndView mv = ha.handle(request, response, handler.getHandler());
HandlerAdapter 調用 Controller 方法,并傳遞請求參數,獲取返回的 ModelAndView
。
4. 參數解析與返回值處理
參數解析
HandlerAdapter 通過 HandlerMethodArgumentResolver
解析請求參數:
內置解析器:Spring MVC 提供多種解析器,例如:
RequestParamMethodArgumentResolver
:解析 @RequestParam
注解的參數。
PathVariableMethodArgumentResolver
:解析路徑變量(如 /users/{id}
)。
RequestBodyArgumentResolver
:解析請求體(如 JSON、XML),需配合 @RequestBody
注解。
自定義解析器:可實現 HandlerMethodArgumentResolver
接口自定義參數解析邏輯。
返回值處理
HandlerAdapter 通過 HandlerMethodReturnValueHandler
處理返回值:
內置處理器:例如:
ViewNameMethodReturnValueHandler
:處理返回視圖名的方法。
ModelAndViewMethodReturnValueHandler
:處理返回 ModelAndView
的方法。
ResponseBodyEmitterReturnValueHandler
:處理異步返回值(如 ResponseEntity
)。
@ResponseBody 注解:若方法標注了 @ResponseBody
,則通過 HttpMessageConverter
將返回值序列化為響應體(如 JSON)。
5. 示例:從請求到 Controller 的完整流程
假設存在以下 Controller:
@RestController@RequestMapping("/api/users")public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public UserDTO getUser(@PathVariable Long id) {return userService.getUserById(id);}}
請求流程:
客戶端發送請求 GET /api/users/123
。
DispatcherServlet 接收請求,調用 RequestMappingHandlerMapping
。
HandlerMapping 根據 URL /api/users/123
和請求方法 GET
,匹配到 UserController.getUser()
方法。
DispatcherServlet 獲取 HandlerAdapter
(即 RequestMappingHandlerAdapter
)。
HandlerAdapter 解析路徑變量 id=123
,并調用 UserController.getUser(123)
。
Controller 方法返回 UserDTO
對象。
由于 @RestController
隱含 @ResponseBody
,HandlerAdapter 通過 HttpMessageConverter
將 UserDTO
序列化為 JSON。
DispatcherServlet 將 JSON 響應返回給客戶端。
6. 攔截器與異常處理
攔截器(Interceptor)
在請求到達 Controller 前后,可通過攔截器執行額外邏輯:
實現 HandlerInterceptor
接口:
public class LoggingInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) {// 請求處理前執行(如日志記錄、權限校驗)return true; // 繼續執行后續流程}@Overridepublic void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView) {// 請求處理后、視圖渲染前執行}@Overridepublic void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) {// 完成請求處理(如資源清理)}}
注冊攔截器:
@Configurationpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/api/**"); // 攔截所有 API 請求}}
異常處理
通過 @ControllerAdvice
和 @ExceptionHandler
統一處理異常:
@ControllerAdvicepublic class GlobalExceptionHandler {@ExceptionHandler(NotFoundException.class)public ResponseEntity<String> handleNotFoundException(NotFoundException ex) {return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());}}
總結
Spring MVC 通過 HandlerMapping 實現 URL 到 Controller 方法的映射,通過 HandlerAdapter 統一調用不同類型的 Handler,并借助 參數解析器 和 返回值處理器 完成請求參數和響應數據的轉換。整個過程由 DispatcherServlet 協調,配合攔截器和異常處理機制,形成了一個完整的請求處理體系。理解這些機制,有助于更高效地開發和調試 Spring MVC 應用。