当前位置: 首页 > news >正文

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链式解析。
http://www.rkmt.cn/news/1403185.html

相关文章:

  • 为Claude Code配置Taotoken作为稳定后备API源的完整指南
  • 硅谷AI风云:Token焦虑、裁员潮与华人创业新机遇
  • IM平台:从沟通工具到协作中枢的进化
  • ChatGPT礼物建议失效真相:当LLM遇上“隐性关系权重”与“文化语境衰减”,你还在靠直觉提问?
  • AI智能体技术架构解析:从MCP到A2A,构建你的Agent军团
  • 超越基础教程:A* Pathfinding Project插件在Unity中的高级应用与性能优化实战
  • 5分钟彻底优化Windows 11:开源工具Win11Debloat让你的电脑快如闪电
  • 2026上海苏州昆山本地装修公司推荐榜 - 资讯焦点
  • 电路可靠性优化:基于EPT模型与灵敏度路径的关键单元识别方法
  • 2025终极指南:用bilili一键下载B站视频和弹幕
  • 云服务可用性档案:从真实故障数据洞察容错机制设计
  • 微信聊天记录永久保存指南:如何完整备份与智能分析你的数字记忆
  • 火狐浏览器 `navigator.clipboard is undefined` 解决方案
  • 观察使用Taotoken Token Plan后月度API成本的变化
  • 矩形QAM盲均衡算法:RRECTCA与IRCA原理、实现与性能分析
  • 戴森球计划蓝图库完全指南:如何用开源方案打造星际自动化工厂
  • 作为个人开发者,我如何使用Taotoken管理多个项目的API密钥
  • IRS辅助RSMA系统鲁棒波束成形设计:应对硬件损伤与CSI误差
  • GFM逆变器同步稳定性:电流电压限幅与PQ解耦的几何分析
  • 协程框架高并发翻车了?三个C++ Web框架实测,结果出乎意料
  • 3D EXIT图分析:解码SLDPC迭代收敛与硬件性能权衡
  • Windows 10安卓子系统反向移植:技术实现与部署深度解析
  • 猫抓浏览器扩展:三步轻松掌握网页资源获取的终极方案
  • 2026哪家装修公司收费合理,没有增项和套路 - 大渝测评
  • Pixverse 视频生成 API 集成指南
  • RRAM神经加速器端到端设计:从算法到电路的电路级验证流程
  • 搭 K8s 环境踩过这 4 个坑,你就能少走半个月弯路【系列一】
  • 有限域GF(2^m)渐近平方根算法:原理、推导与硬件实现
  • GEO生成引擎优化:2026年AI搜索时代的流量新变量
  • 高洁净循环泵厂家排名:半导体制药行业优选指南 - 资讯焦点