Spring官网的MVC模块介绍

  1. 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:
SpringMVC之请求源码流程 - 图1
弊端:

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

所以SpringMVC就是在Servlet的基础上进行了封装,帮我们把这些麻烦的事情都给做了.

SpringMVC实现方式

  • 基于XML的实现方式:
    • 给Servlet容器配置一个DispatcherServlet
    • 添加SpringMVC的配置信息
  • 继承类HttpRequestHandler方式
  • 注解方式

    • 配置控制器@Controller和处理方法的映射—@RequstMapping 即可

      SpringMVC请求原理

      说白了就是用一个DispatcherServlet封装了一个Servlet的调度中心,由调度中心帮我们调用我们的处理方法,
      在这个过程中调度中心委托给各个组件执行具体工作,比如帮我们去映射方法请求、帮我们解析参数、调用处理方法、响应数据和页面等
      这就相当于你在家自己做饭和去饭店吃饭的区别了,在家你买菜、洗菜、蒸饭、炒菜、洗碗都得自己来,饭店都给你做好了,
      你只要吩咐服务员说你吃什么、就能得到响应,然而,你只是说了吃什么(请求),后厨(DispatcherServlet)就有配菜员给你找到菜单上对应的食材(映射)、切菜员切菜(解析参数)、厨师给你炒菜(调用处理方法)、装盘(处理返回值)、炒完给你端出来(响应).

      SpringMVC的具体执行流程

      SpringMVC是围绕前端控制器模式设计的,其中中央 Servlet DispatcherServlet 为请求处理流程提供统一调度,实际工作则交给可配置组件执行.
      这个模型是灵活的且开放的,我们可以通过自己去定制这些组件从而进行定制自己的工作流
      SpringMVC之请求源码流程 - 图2
  • DispatcherServlet: 前端调度器,负责将请求拦截下来分发到各控制器方法中

  • HandlerMapping: 负责根据请求的URL和配置@RequestMapping映射去匹配,匹配到会返回Handler(具体控制器的方法)
  • HandlerAdaper: 负责调用Handler具体的方法, 返回视图的名字,Handler将它封装到ModelAndView(封装视图名,request域的数据)
  • ViewReslover: 根据ModelAndView里面的视图名地址去找到具体的Jsp封装在View对象中
  • View: 进行视图渲染,将Jsp转换成html内容,这是Servlet容器的事情,最终response到的客户端

具体流程如下:

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

    DispatcherServlet#doDispatch

    1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    2. HttpServletRequest processedRequest = request;
    3. HandlerExecutionChain mappedHandler = null;
    4. boolean multipartRequestParsed = false;
    5. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    6. try {
    7. ModelAndView mv = null;
    8. Exception dispatchException = null;
    9. try {
    10. processedRequest = checkMultipart(request);
    11. multipartRequestParsed = (processedRequest != request);
    12. // 进行映射
    13. mappedHandler = getHandler(processedRequest);
    14. if (mappedHandler == null) {
    15. noHandlerFound(processedRequest, response);
    16. return;
    17. }
    18. // 找到最合适的HandlerAdapter
    19. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    20. // Process last-modified header, if supported by the handler. HTTP缓存相关
    21. String method = request.getMethod();
    22. boolean isGet = HttpMethod.GET.matches(method);
    23. if (isGet || HttpMethod.HEAD.matches(method)) {
    24. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    25. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    26. return;
    27. }
    28. }
    29. // 前置拦截器
    30. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    31. // 返回false就不进行后续处理了
    32. return;
    33. }
    34. // Actually invoke the handler.
    35. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    36. if (asyncManager.isConcurrentHandlingStarted()) {
    37. return;
    38. }
    39. // 如果mv有 视图没有,给你设置默认视图
    40. applyDefaultViewName(processedRequest, mv);
    41. //后置拦截器
    42. mappedHandler.applyPostHandle(processedRequest, response, mv);
    43. }
    44. catch (Exception ex) {
    45. dispatchException = ex;
    46. }
    47. catch (Throwable err) {
    48. // As of 4.3, we're processing Errors thrown from handler methods as well,
    49. // making them available for @ExceptionHandler methods and other scenarios.
    50. dispatchException = new NestedServletException("Handler dispatch failed", err);
    51. }
    52. // 渲染视图
    53. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    54. }
    55. catch (Exception ex) {
    56. triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    57. }
    58. catch (Throwable err) {
    59. triggerAfterCompletion(processedRequest, response, mappedHandler,
    60. new NestedServletException("Handler processing failed", err));
    61. }
    62. finally {
    63. if (asyncManager.isConcurrentHandlingStarted()) {
    64. // Instead of postHandle and afterCompletion
    65. if (mappedHandler != null) {
    66. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    67. }
    68. }
    69. else {
    70. // Clean up any resources used by a multipart request.
    71. if (multipartRequestParsed) {
    72. cleanupMultipart(processedRequest);
    73. }
    74. }
    75. }
    76. }