Spring源码 第六篇:Spring 5 源码深度拆解:SpringMVC 全流程核心原理

Spring源码 第六篇:Spring 5 源码深度拆解:SpringMVC 全流程核心原理 引言接下来基于 Spring 源码主要介绍以下几个问题EnableWebMvc到底干了什么请求从浏览器进来完整经过哪些组件HandlerMapping、HandlerAdapter、ViewResolver分别干嘛用参数是怎么绑定到方法入参的返回值是怎么变成 JSON / 页面 / 异常信息的拦截器、异常处理器在源码中哪个节点执行一、核心前提SpringMVC 整体架构1. 一句话概括流程浏览器请求 →DispatcherServlet分发 → 找到对应Controller方法 → 执行方法 → 处理返回值 → 响应给浏览器。2. 九大核心组件面试必背组件作用HandlerMapping根据请求 URL 找到对应的Controller方法HandlerAdapter统一执行Controller方法的适配器ThemeResolver不同主题间动态切换ViewResolver视图解析器把逻辑视图名转为真实视图HandlerExceptionResolver全局异常处理器LocaleResolver国际化解析器MultipartResolver文件上传解析器RequestToViewNameTranslator默认视图名转换器FlashMapManager重定向数据管理器二、入口EnableWebMvc 源码解析EnableWebMvc是 JavaConfig 方式手动启用 SpringMVC 的注解等价于 XML 中的mvc:annotation-driven/。注意Spring Boot 项目不推荐、也不需要加它。Retention(RetentionPolicy.RUNTIME)Target(ElementType.TYPE)DocumentedImport(DelegatingWebMvcConfiguration.class)publicinterfaceEnableWebMvc{}核心就是导入DelegatingWebMvcConfiguration。它会自动向容器注册RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver各种参数解析器、返回值处理器消息转换器MappingJackson2HttpMessageConverter一句话EnableWebMvc 自动装配 SpringMVC 全套核心组件。三、容器启动SpringMVC 初始化流程1. Tomcat 启动 → 加载 DispatcherServletDispatcherServlet本质是一个Servlet生命周期init()→service()→destroy()。2. init 阶段核心初始化九大组件protectedvoidinitStrategies(ApplicationContextcontext){initMultipartResolver(context);// 文件上传initLocaleResolver(context);// 国际化initThemeResolver(context);initHandlerMappings(context);// 路由映射initHandlerAdapters(context);// 执行适配器initHandlerExceptionResolvers(context);// 异常处理initRequestToViewNameTranslator(context);initViewResolvers(context);// 视图解析initFlashMapManager(context);}这就是 SpringMVC 启动时干的所有事。四、请求执行全流程浏览器发送 HTTP 请求Tomcat 接收请求交给 DispatcherServletdoService(req, resp)doDispatch(req, resp)【核心总调度方法】1. getHandler(request)遍历 HandlerMapping找到对应 Controller 方法2. getHandlerAdapter(handler)找到能执行该方法的适配器3. 执行拦截器 applyPreHandle调用 preHandle4. adapter.handle(request, response, handler)真正执行 Controller 方法内部参数解析 → 执行方法 → 得到返回值5. 处理返回值JSON/视图/文件等6. 执行拦截器 applyPostHandle调用 postHandle7. 异常处理执行异常解析器8. 渲染视图如果不是直接响应9. 执行拦截器 triggerAfterCompletion调用 afterCompletion响应回浏览器五、核心方法doDispatch源码解析doDispatch源码部分内容如下protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse){HttpServletRequestprocessedRequestrequest;HandlerExecutionChainmappedHandlernull;try{ModelAndViewmvnull;ExceptiondispatchExceptionnull;try{// 1. 找到对应的处理器Controller方法mappedHandlergetHandler(processedRequest);// 2. 找到适配器HandlerAdapterhagetHandlerAdapter(mappedHandler.getHandler());// 3. 执行拦截器 preHandleif(!mappedHandler.applyPreHandle(processedRequest,response)){return;}// 4. 【真正调用Controller方法】mvha.handle(processedRequest,response,mappedHandler.getHandler());// 5. 执行拦截器 postHandlemappedHandler.applyPostHandle(processedRequest,response,mv);}catch(Exceptionex){dispatchExceptionex;}// 6. 处理结果、渲染视图、异常处理processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException);}catch(Exceptionex){// 最终拦截器mappedHandler.triggerAfterCompletion(processedRequest,response,ex);}}六、关键节点深度拆解1. 根据 URL 找到 Controller 方法流程图位置doDispatch→1. getHandler(request)所在类org.springframework.web.servlet.DispatcherServlet所在方法doDispatch核心代码mappedHandler getHandler(processedRequest);核心实现遍历容器中所有HandlerMapping由RequestMappingHandlerMapping负责匹配建立并返回url→HandlerMethod的映射封装为HandlerExecutionChain包含所有拦截器2. 找到执行方法的适配器流程图位置doDispatch→2. getHandlerAdapter(handler)所在类DispatcherServlet所在方法doDispatch核心代码HandlerAdapter ha getHandlerAdapter(mappedHandler.getHandler());核心实现遍历所有HandlerAdapter匹配到RequestMappingHandlerAdapter继承自AbstractHandlerMethodAdapter用于统一执行RequestMapping方法3. 执行拦截器preHandle流程图位置doDispatch→3. 执行拦截器 preHandle所在类DispatcherServlet所在方法doDispatch核心代码if(!mappedHandler.applyPreHandle(processedRequest,response)){return;}实际执行类HandlerExecutionChainbooleanapplyPreHandle(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{for(inti0;ithis.interceptors.size();i){HandlerInterceptorinterceptorthis.interceptors.get(i);if(!interceptor.preHandle(request,response,this.handler)){triggerAfterCompletion(request,response,null);returnfalse;}this.interceptorIndexi;}returntrue;}关键点任一拦截器返回false直接中断请求并执行已通过拦截器的afterCompletion。4. 真正执行 Controller 方法流程图位置doDispatch→4. adapter.handle(…)所在类DispatcherServlet所在方法doDispatch核心代码mv ha.handle(processedRequest, response, mappedHandler.getHandler());实际执行类RequestMappingHandlerAdapter4.1 参数解析调度入口RequestMappingHandlerAdapter执行类ServletInvocableHandlerMethod遍历所有参数解析器处理RequestParamPathVariableRequestBodyRequestHeaderServletRequest/HttpServletResponse4.2 反射执行目标方法所在类InvocableHandlerMethod方法doInvokereturnmethod.invoke(getBean(),getArguments());执行链路ha.handle() ↓ handleInternal() ↓ invokeHandlerMethod() ↓ invocableMethod.invokeAndHandle() ↓ invokeForRequest() ↓ 【doInvoke()】 ← 最终执行到这里 ↓ method.invoke(bean, args) → 反射调用Controller方法5. 处理返回值JSON / 视图流程图位置 执行方法后 →5. 处理返回值所在类ServletInvocableHandlerMethod方法invokeAndHandle核心组件HandlerMethodReturnValueHandlerComposite常见实现RequestResponseBodyMethodProcessor处理ResponseBody→ JSONViewNameMethodReturnValueHandler处理字符串视图名ModelAndViewMethodReturnValueHandler处理ModelAndView6. 执行拦截器postHandle流程图位置doDispatch→6. 执行拦截器 postHandle所在类DispatcherServlet所在方法doDispatch核心代码mappedHandler.applyPostHandle(processedRequest, response, mv);实际执行类HandlerExecutionChainvoidapplyPostHandle(HttpServletRequestrequest,HttpServletResponseresponse,ModelAndViewmv)throwsException{for(intithis.interceptors.size()-1;i0;i--){HandlerInterceptorinterceptorthis.interceptors.get(i);interceptor.postHandle(request,response,this.handler,mv);}}注意postHandle是逆序执行。preHandle正序执行postHandle逆序执行afterCompletion逆序执行7. 渲染视图流程图位置doDispatch→7. 渲染视图所在类DispatcherServlet所在方法processDispatchResult核心代码render(mv, request, response);逻辑通过ViewResolver解析视图名得到View执行view.render (model, request, response)适用于 JSP/Thymeleaf/Freemarker 等模板8. 执行拦截器afterCompletion流程图位置doDispatch→8. 执行拦截器 afterCompletion所在类DispatcherServlet位置doDispatch最终catch块核心代码mappedHandler.triggerAfterCompletion(processedRequest, response, ex);实际执行类HandlerExecutionChainvoidtriggerAfterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Exceptionex)throwsException{for(intithis.interceptorIndex;i0;i--){HandlerInterceptorinterceptorthis.interceptors.get(i);interceptor.afterCompletion(request,response,this.handler,ex);}}关键点无论正常返回还是抛异常一定执行。七、高频面试题SpringMVC 执行流程是什么Tomcat 启动初始化DispatcherServlet加载 Spring 容器注册所有 SpringMVC 组件请求进入doDispatch根据 URL 找到Controller方法执行拦截器前置参数解析 → 调用方法处理返回值JSON/视图执行拦截器后置渲染/响应最终拦截器DispatcherServlet作用答统一入口总调度管理九大组件。HandlerMapping和HandlerAdapter区别答Mapping负责找方法Adapter负责执行方法。ResponseBody原理答返回值处理器 JSON 消息转换器。拦截器和过滤器区别FilterServlet 规范所有容器都支持拦截所有请求。InterceptorSpringMVC 组件能访问 Spring 容器。参数是如何注入的答ArgumentResolver链式解析。