Spring MVC 底层工作流程+源码分析
Spring MVC 将DispatcherServlet作为前端控制器,所有请求都先汇聚于此,再由它委派给其他组件协同处理。
Spring MVC 核心流程图
Spring MVC 核心工作流程(含源码关键调用点)
流程详解(对照源码行号)
| 步骤 | 角色 / 关键代码位置 | 说明 |
|---|---|---|
| 1 | DispatcherServlet.doDispatch()line 920+ | 所有请求入口,开始调度。 |
| 2 | getHandler()-> 遍历handlerMappings | 通过 URL 找到HandlerExecutionChain(含Handler+Interceptor列表)。 |
| 3 | getHandlerAdapter() | 根据Handler类型找到能执行它的适配器(如RequestMappingHandlerAdapter)。 |
| 4 | applyPreHandle() | 依次执行每个拦截器的preHandle方法,若返回false则请求短路。 |
| 5 | ha.handle() | 适配器调用实际Controller方法(通过反射),并封装返回值为ModelAndView。 |
| 6 | applyPostHandle() | 执行拦截器的postHandle方法(在Controller之后、视图渲染之前)。 |
| 7 | processDispatchResult() | 统一处理ModelAndView或异常。 |
| 8 | render()->ViewResolver.resolveViewName() | 根据逻辑视图名(如"userList")解析出View(如InternalResourceView)。 |
| 9 | View.render() | 将模型数据与视图合并(如 JSP 渲染),输出到HttpResponse。 |
| 10 | triggerAfterCompletion() | 执行拦截器的afterCompletion方法(无论是否异常,最终清理)。 |
图中使用了子图
DispatcherServlet和ViewResolver,并用不同颜色区分组件类型,流程箭头清晰标注了步骤序号,方便和源码对应。
精简版总结(一句话 + 一张表)
DispatcherServlet 接收请求 → HandlerMapping 定位 → HandlerAdapter 执行 → 拦截器干预 → 返回 ModelAndView → ViewResolver 渲染 → 输出响应
| 阶段 | 组件 | 源码方法 |
|---|---|---|
| 接收请求 | DispatcherServlet | doDispatch() |
| 定位处理器 | HandlerMapping | getHandler() |
| 执行处理器 | HandlerAdapter | ha.handle() |
| 视图解析 | ViewResolver | resolveViewName() |
| 视图渲染 | View | render() |
| 拦截器回调 | Interceptor | preHandle/postHandle/afterCompletion |
组件分析
核心组件(五大关键角色)
| 组件 | 职责 |
|---|---|
| DispatcherServlet | 中央调度器,接收请求并分发给其他组件 |
| HandlerMapping | 根据请求 URL 找到能处理它的Handler(即@RequestMapping方法) |
| HandlerAdapter | 适配器:确保不同类型的Handler能以统一方式被调用执行 |
| ViewResolver | 根据逻辑视图名(如"hello")解析出真正的View对象(如hello.jsp) |
| View | 负责视图渲染,将Model数据填充到视图中 |
执行流程:源码逐步拆解
1. 请求入口:doDispatch(Request, Response)
DispatcherServlet的doDispatch是处理所有请求的核心调度方法:
protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{HttpServletRequestprocessedRequest=request;HandlerExecutionChainmappedHandler=null;ModelAndViewmv=null;// ... 上下文设置、异步处理等 ...try{// ✅ 1. 检查文件上传processedRequest=checkMultipart(request);// ✅ 2. 获取处理器执行链 (Handler + Interceptors)mappedHandler=getHandler(processedRequest);if(mappedHandler==null){noHandlerFound(processedRequest,response);return;}// ✅ 3. 获取支持该 Handler 的适配器HandlerAdapterha=getHandlerAdapter(mappedHandler.getHandler());// ✅ 4. 执行所有拦截器的 preHandle 方法if(!mappedHandler.applyPreHandle(processedRequest,response)){return;// 如果某个拦截器返回 false,流程中断}// ✅ 5. 核心!调用 Handler 执行业务逻辑,返回 ModelAndViewmv=ha.handle(processedRequest,response,mappedHandler.getHandler());// ✅ 6. 执行所有拦截器的 postHandle 方法mappedHandler.applyPostHandle(processedRequest,response,mv);// ✅ 7. 最终视图渲染与异常处理processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException);}catch(Exceptionex){// 统一异常处理}}2. 处理器映射:getHandler(Request)
以下代码展示了如何为请求找到匹配的处理器:
protectedHandlerExecutionChaingetHandler(HttpServletRequestrequest){for(HandlerMappinghm:this.handlerMappings){HandlerExecutionChainhandler=hm.getHandler(request);if(handler!=null){returnhandler;// 返回包含 Handler 和拦截器链的对象}}returnnull;}3. 获取适配器:getHandlerAdapter(Handler)
以下代码展示了如何获取适配器:
protectedHandlerAdaptergetHandlerAdapter(Objecthandler){for(HandlerAdapterha:this.handlerAdapters){if(ha.supports(handler)){returnha;}}thrownewServletException("No adapter for handler...");}4. 业务执行:ha.handle(...) -> ModelAndView
适配器的handle方法内部会:
- 解析请求参数与
@PathVariable - 执行数据验证与类型转换
- 通过反射调用
Controller的具体方法 - 将返回值(数据、视图名)封装为
ModelAndView对象
5. 最终响应:processDispatchResult(...)
processDispatchResult方法会调用ViewResolver将ModelAndView中的逻辑视图名解析为物理视图(如 JSP),并执行渲染。
privatevoidprocessDispatchResult(HttpServletRequestrequest,HttpServletResponseresponse,HandlerExecutionChainmappedHandler,ModelAndViewmv,Exceptionexception)throwsException{// 统一异常处理// ...if(mv!=null){// 调用 ViewResolver 解析逻辑视图名render(mv,request,response);}// 执行所有拦截器的 afterCompletion 方法if(mappedHandler!=null){mappedHandler.triggerAfterCompletion(request,response,null);}}一个请求进来,从前到后的核心处理链就完整走通了:DispatcherServlet→HandlerMapping定位方法 →HandlerAdapter适配执行 → 反射调用业务代码,返回ModelAndView→ViewResolver与View渲染响应 → 中间穿插着Interceptor的拦截逻辑。
将DispatcherServlet类比为公司的前台总机,所有访客(请求)先到这里。总机根据来意查看地图(HandlerMapping)找到对应部门,找到后安排行政助理(HandlerAdapter)对接,业务办完后秘书将结果返回前台,再由总机指定专员(ViewResolver)制作最终的回执文件(View)交给访客。
