Spring MVC请求处理流程
Spring MVC 是基于 Servlet 的 Web 框架。理解请求处理流程,有助于自定义扩展和排查问题。
核心组件
| 组件 |
作用 |
| DispatcherServlet |
前端控制器,统一接收请求 |
| HandlerMapping |
请求 -> Handler 的映射 |
| HandlerAdapter |
适配不同的 Handler 类型 |
| Handler |
处理器(Controller) |
| ViewResolver |
视图解析 |
| View |
视图渲染 |
请求处理流程
HTTP Request | v DispatcherServlet.doDispatch() | v 1. 调用 HandlerMapping 获取 HandlerExecutionChain ├── Handler(Controller 方法) └── Interceptor 列表 | v 2. 调用 HandlerAdapter 执行 Handler | v 3. 参数解析(HandlerMethodArgumentResolver) ├── @RequestParam ├── @PathVariable ├── @RequestBody └── ... | v 4. 执行 Controller 方法 | v 5. 返回值处理(HandlerMethodReturnValueHandler) ├── @ResponseBody -> HttpMessageConverter ├── String -> View 名称 └── ModelAndView | v 6. 执行 Interceptor 的 postHandle | v 7. 视图解析和渲染(非 @ResponseBody) | v 8. 执行 Interceptor 的 afterCompletion | v HTTP Response
|
DispatcherServlet 源码分析
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } finally { } }
|
HandlerMapping
常见实现
HandlerMapping ├── BeanNameUrlHandlerMapping # 根据 Bean 名称映射(旧) ├── SimpleUrlHandlerMapping # 简单 URL 映射 └── RequestMappingHandlerMapping # @RequestMapping 注解映射(默认)
|
RequestMappingHandlerMapping
@Controller @RequestMapping("/users") public class UserController { @GetMapping("/{id}") @ResponseBody public User getUser(@PathVariable Long id) { return userService.findById(id); } }
|
映射信息存储:
Map<T, HandlerMethod> mappingLookup Map<T, MappingRegistration<T>> registry
|
HandlerAdapter
常见实现
HandlerAdapter ├── HttpRequestHandlerAdapter # HttpRequestHandler ├── SimpleControllerHandlerAdapter # Controller 接口 ├── SimpleServletHandlerAdapter # Servlet └── RequestMappingHandlerAdapter # @RequestMapping(默认)
|
RequestMappingHandlerAdapter
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); Object[] args = resolveArguments(request, handlerMethod, binderFactory); Object returnValue = handlerMethod.invoke(args); return handleReturnValue(returnValue, handlerMethod); }
|
参数解析
常用参数解析器
| 注解/类型 |
解析器 |
说明 |
| @RequestParam |
RequestParamMethodArgumentResolver |
请求参数 |
| @PathVariable |
PathVariableMethodArgumentResolver |
URL 路径变量 |
| @RequestBody |
RequestResponseBodyMethodProcessor |
JSON/XML 反序列化 |
| @ModelAttribute |
ServletModelAttributeMethodProcessor |
表单对象绑定 |
| HttpServletRequest |
ServletRequestMethodArgumentResolver |
Servlet 请求 |
| @RequestHeader |
RequestHeaderMethodArgumentResolver |
请求头 |
自定义参数解析器
public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(CurrentUser.class) && parameter.getParameterType() == User.class; } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { return UserContext.getCurrentUser(); } }
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new CurrentUserArgumentResolver()); } }
|
返回值处理
常用返回值处理器
| 返回值类型 |
处理器 |
说明 |
| @ResponseBody |
RequestResponseBodyMethodProcessor |
JSON/XML 序列化 |
| String |
ViewNameMethodReturnValueHandler |
视图名称 |
| ModelAndView |
ModelAndViewMethodReturnValueHandler |
模型和视图 |
| void |
ViewNameMethodReturnValueHandler |
默认视图 |
HttpMessageConverter
@ResponseBody | v RequestResponseBodyMethodProcessor | v HttpMessageConverter ├── MappingJackson2HttpMessageConverter # JSON ├── MappingJackson2XmlHttpMessageConverter # XML └── StringHttpMessageConverter # String
|
Interceptor 执行顺序
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/login"); registry.addInterceptor(new LogInterceptor()) .addPathPatterns("/**"); } }
|
请求 | ├── AuthInterceptor.preHandle() -> true │ ├── LogInterceptor.preHandle() -> true │ │ ├── Controller 执行 │ │ ├── LogInterceptor.postHandle() │ ├── AuthInterceptor.postHandle() │ ├── 视图渲染 │ ├── LogInterceptor.afterCompletion() ├── AuthInterceptor.afterCompletion()
|
异常处理
@ExceptionHandler
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) @ResponseBody public Result<?> handleBusiness(BusinessException e) { return Result.fail(e.getCode(), e.getMessage()); } @ExceptionHandler(Exception.class) @ResponseBody public Result<?> handleException(Exception e) { return Result.fail(500, "系统错误"); } }
|
异常处理流程
Controller 抛出异常 | v DispatcherServlet.processHandlerException() | v 遍历 HandlerExceptionResolver ├── ExceptionHandlerExceptionResolver # @ExceptionHandler ├── ResponseStatusExceptionResolver # @ResponseStatus └── DefaultHandlerExceptionResolver # Spring 默认异常 | v 生成 ModelAndView 或重新抛出
|
总结
Spring MVC 的请求处理流程清晰分层:
- DispatcherServlet:统一入口
- HandlerMapping:路由匹配
- HandlerAdapter:适配执行
- ArgumentResolver:参数解析
- Controller:业务处理
- ReturnValueHandler:返回值处理
- ViewResolver:视图解析
- Interceptor:横切处理
理解这个流程,可以灵活扩展 Spring MVC 的功能,如自定义参数解析、返回值处理、异常处理等。