深入解析SpringMVC执行流程:从源码到架构设计

你好,我是柳岸花开。

Spring官网对MVC模块的介绍:

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name “Spring Web MVC” comes from the name of its source module (spring-webmvc) but it is more commonly known as “Spring MVC”.

Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中。正式名称“Spring Web MVC”来自其源模块的名称(spring-webmvc),但它通常被称为“Spring MVC”。

从Servlet到SpringMVC

最典型的MVC模式是JSP + servlet + javabean。然而,传统Servlet存在许多弊端:

  1. XML下配置Servlet的映射非常麻烦,开发效率低。
  2. 必须要继承父类、重写方法,侵入性强。
  3. 如果想在一个Servlet中处理同一业务模块的功能分发给不同方法进行处理非常麻烦。
  4. 参数解析麻烦:单个参数(转换类型)-> POJO对象,Json文本-> POJO对象。
  5. 数据响应麻烦:POJO对象-> Json,Content-type。
  6. 跳转页面麻烦:对path的控制,如果使用其他模板也很麻烦,设置编码麻烦。

SpringMVC的具体执行流程

Spring MVC围绕前端控制器模式设计,其中中央Servlet DispatcherServlet 为请求处理流程提供统一调度,实际工作则交给可配置组件执行。这个模型灵活且开放,可以定制这些组件从而定制自己的工作流。

主要组件及其职责

  1. DispatcherServlet:前端调度器,负责将请求拦截下来分发到各控制器方法中。
  2. HandlerMapping:负责根据请求的URL和配置的 @RequestMapping映射去匹配,匹配到会返回Handler(具体控制器的方法)。
  3. HandlerAdapter:负责调用Handler(具体的方法),返回视图的名字,并将其封装到 ModelAndView中。
  4. ViewReslover:根据 ModelAndView里面的视图名地址去找到具体的视图对象。
  5. View:进行视图渲染(将JSP转换成HTML内容),最终响应到客户端。

DispatcherServlet处理流程源码解析

alt
  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用处理器映射器HandlerMapping。
  • 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
  1. DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter,执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
  2. 执行处理器Handler(Controller,也叫页面控制器)。
  • Handler执行完成返回ModelAndView
  • HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
  1. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  • ViewReslover解析后返回具体View
  1. DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
  2. DispatcherServlet响应用户。

DispatcherServletdoDispatch方法体现了整个请求流程。以下是其源码和对应的解释:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   try {
      try {
         // 文件上传相关
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // DispatcherServlet收到请求调用处理器映射器HandlerMapping
         // 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

         // Process last-modified header, if supported by the handler.  HTTP缓存相关
         String method = request.getMethod();
         boolean isGet = HttpMethod.GET.matches(method);
         if (isGet || HttpMethod.HEAD.matches(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }
         // 前置拦截器
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            // 返回false就不进行后续处理了
            return;
         }

         // 执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
         // 执行处理器Handler(Controller,也叫页面控制器)
         // Handler执行完成返回ModelAndView
         // HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }
         // 如果没有视图,给你设置默认视图  json忽略
         applyDefaultViewName(processedRequest, mv);
         // 后置拦截器
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      catch (Throwable err) {
         // As of 4.3, we're processing Errors thrown from handler methods as well,
         // making them available for @ExceptionHandler methods and other scenarios.
         dispatchException = new NestedServletException("Handler dispatch failed", err);
      }
      // DispatcherServlet将ModelAndView传给ViewReslover视图解析器
      // ViewReslover解析后返回具体View
      // DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)
      // DispatcherServlet响应用户
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
   }
   catch (Throwable err) {
      triggerAfterCompletion(processedRequest, response, mappedHandler,
            new NestedServletException("Handler processing failed", err));
   }
   finally {
      if (asyncManager.isConcurrentHandlingStarted()) {
         // Instead of postHandle and afterCompletion
         if (mappedHandler != null) {
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
         }
      }
      else {
         // Clean up any resources used by a multipart request
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

通过上述图示和流程解析,可以清晰地了解SpringMVC的处理过程及其关键组件的职责分工。这种灵活且开放的设计模式,使得SpringMVC在Web开发中得到了广泛的应用。

👇关注我,下期了解👇 ​ SpringMVC源码 ​ ​ alt ​ ​ 回复 222,获取Java面试题合集 ​ 关于我 ​ 一枚爱折腾的Java程序猿,专注Spring干货。把路上的问题记录下来,帮助那些和我一样的人。 ​ 好奇心强,喜欢并深入研究古天文。 ​ 崇尚 个人系统创建,做一些时间越长越有价值的事情。思考 把时间留下来 又 每刻都是新的。

本文由 mdnice 多平台发布

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-15 18:18:06       53 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-15 18:18:06       56 阅读
  3. 在Django里面运行非项目文件

    2024-07-15 18:18:06       46 阅读
  4. Python语言-面向对象

    2024-07-15 18:18:06       57 阅读

热门阅读

  1. Nginx的重定向

    2024-07-15 18:18:06       22 阅读
  2. websocket中的STOMP 协议:sockjs-client 和 stompjs

    2024-07-15 18:18:06       25 阅读
  3. 等保测评的智能化与自动化展望

    2024-07-15 18:18:06       24 阅读
  4. 程序员养生指南:守护健康,高效编码

    2024-07-15 18:18:06       13 阅读
  5. YoloV8改进策略:卷积篇Kan行天下之小波Kan

    2024-07-15 18:18:06       14 阅读
  6. FastJson详解

    2024-07-15 18:18:06       15 阅读
  7. HTML-VUE页面调用android 客户端网络请求并返回数据

    2024-07-15 18:18:06       15 阅读
  8. C++ 左值与右值

    2024-07-15 18:18:06       15 阅读
  9. 网络协同新纪元:Eureka引领分布式网络管理革命

    2024-07-15 18:18:06       17 阅读
  10. deepstream tracker NvDCF未实现跟踪

    2024-07-15 18:18:06       16 阅读
  11. Mybatis

    Mybatis

    2024-07-15 18:18:06      12 阅读
  12. Kafka 入门指南

    2024-07-15 18:18:06       11 阅读