• 【Spring MVC研究】DispatcherServlet如何处理请求(doDispatcher方法)



    本文以“最经典”的情况分析了 DispatcherServlet 处理请求的全部过程。通读全文,读者应该对总体框架有一定的认识,且要求今后能有能力把 mvc 的其他组件原理“嵌入到总体框架中”。

    1. 最经典的MVC的使用情况

    这个过程很长,设计的到 web 组件很多,所以需要以一个最常见的情况作为“经典情况”来简化分析过程。突破之后再在对总体流程和框架的基础上,往上面新的补充内容。为了方便我讲解,我以:
    “经典情况”是:Controller 中的@RequestMapping,方法的参数贴了@RequestParam注解,返回值上贴了@ResponseBody注解

    搞完“经典情况”,后续的其他 mvc 组件作者会一个一个的分析。

    2. 经典情况相关的组件

    RequestMappingHandlerMapping(请求映射器

    功能:把请求 request 映射到 handler;根据路径匹配
    对应关系:只要我们的 Controller 写的路径匹配上了请求就可以了,假设匹配上。

    HandlerMethod(处理请求

    功能:具体处理请求的
    对应关系:对应是 Controller 中的方法

    HandlerExecutionChain(处理器链

    功能:等于“处理器” + “匹配的拦截器
    对应关系:这里就是等于:“HandlerMethod + 匹配到的拦截器MappedInterceptor

    RequestMappingHandlerAdapter(对HandlerExecutionChain 再次包装)

    记住:反正就是由RequestMappingHandlerAdapter 开始执行的就可以了。

    RequestParamMethodArgumentResolver参数解析器

    功能:专门处理 @RequestParam 注解的
    对应关系:从请求 request 中解析出参数(调用 ServletRequest的 getParameterValues方法)

    RequestResponseBodyMethodProcessor(返回值处理器)

    功能:专门刚好处理 @ResponseBody注解。

    3. 执行

    3.1. 先看DispatcherServlet的总体过程

    DispatcherServlet 的doDispatch方法的总体执行过程:

    • getHandler(1)
    • getHandlerAdapter(2)
    • applyPreHandle(3)
    • handle(重点:真正处理)(4)
    • applyPostHandle(5)

    在(1)处得到 HandlerExecutionChain,包含 HandlerMethodMappedInterceptor
    在(2)处得到 RequestMappingHandlerAdapter
    在(3)处,执行MappedInterceptorpreHandle方法
    在(4)处,执行 RequestMappingHandlerAdapterhandler方法
    在(5)处,执行MappedInterceptorpostHandle方法

    3.2. 再看RequestMappingHandlerAdapter的总体过程

    继续看 RequestMappingHandlerAdapterhandler方法的总体过程:

    注意:执行顺序是从左到右从上到下执行的

    • 封装为ServletInvocableHandlerMethod(1)
    • invokeAndHandle
      • invokeForRequest
        • getMethodArgumentValues(解析参数)
          • resolveArgument解析参数
            • getArgumentResolver(得到“参数解析器”)
            • resolveArgument(真正解析)
        • doInvoke(具体执行)
      • handleReturnValue(处理返回值)
        • selectHandler
        • handleReturnValue
    • getModelAndView(2)

    主要就只有 3 个关键过程(上面已加粗说明):
    1、按 Controller 方法的要求解析参数。用的是 RequestParamMethodArgumentResolver
    2、执行 Controller 方法。
    3、处理 Controller 方法的返回值。用的是 RequestResponseBodyMethodProcessor
    下面简单提一下其他过程(按序号):
    在(1)处,把真正的执行的组件HandlerMethod 一顿疯狂包装成ServletInvocableHandlerMethod

    比如就包装了 web 数据绑定器:WebDataBinder

    在(2)处,处理视图,现在都是前后端开发,不用视图技术了。作者不讲,略,自己搞。

    3.2.1. RequestParamMethodArgumentResolver

    • 支持的参数

    在它的 supportsParameter 方法中,表明了支持“参数上贴了@RequestParam注解的参数”

    • 执行解析参数

    1、 调用RequestParamMethodArgumentResolver的resolveArgument方法,
    2、 会调用到RequestParamMethodArgumentResolver 的resolveName方法
    3、会调用到解析文件的multipartRequest方法 和 从请求获取参数的 request.getParameterValues方法
    4、解析之后还没有结束,还需要转换成 Controller 方法需要的参数类型(略,这就是另外的小细节故事了)

    截止目前:也就通过从请求中获取参数完成了 Controller 方法参数的解析,

    3.2.2. 反射调用 Controller 的方法

    没什么好讲的,反射调用 Controller 的方法。

    3.2.3. RequestResponseBodyMethodProcessor

    • 支持的类型

    在supportsReturnType方法中表明了支持的类型是方法上@ResponseBody注解

    • 处理返回值

    1、会调用到RequestResponseBodyMethodProcessor 的 handleReturnValue方法
    2、会调用writeWithMessageConverters方法
    3、最后直接调用“消息转换器”messageConverters把“返回值写到流里面去了”

    注意:既然既然写到响应流 response 里面去了,响应就结束了,后面的视图处理过程就没了。

    4. 总结

    读完全文,读者要求掌握以下组件的工作情况。(对细节不需要苛责,但是一定要能知道** 组件的功能 ****组件在流程中的位置**

    • RequestMappingHandlerMapping(请求映射器
    • HandlerMethod(处理请求
    • HandlerExecutionChain(处理器链
    • RequestMappingHandlerAdapter(对HandlerExecutionChain 再次包装)
    • RequestParamMethodArgumentResolver(参数解析器)
    • RequestResponseBodyMethodProcessor(返回值处理器)
  • 相关阅读:
    JVM中的堆的新生代、老年代、永久代
    【c++基础】第三章 宏观部分:面向对象之类的层次结构与相互关系
    Python学习笔记(04)
    Java项目—停车场管理系统(附源码+资料课件)
    MySQL基础必会,简单易懂
    如何进行网站测试
    PAT 1029 Median(25分)
    分类预测 | MATLAB实现WOA-LSTM鲸鱼算法优化长短期记忆网络数据分类预测
    【C++】topk问题
    Mysql 学习总结(89)—— Mysql 库表容量统计
  • 原文地址:https://blog.csdn.net/yuchangyuan5237/article/details/133698828