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

文章目录

  • [1. 最经典的MVC的使用情况](#1. 最经典的MVC的使用情况)
  • [2. 经典情况相关的组件](#2. 经典情况相关的组件)
  • [3. 执行](#3. 执行)
    • [3.1. 先看DispatcherServlet的总体过程](#3.1. 先看DispatcherServlet的总体过程)
    • [3.2. 再看`RequestMappingHandlerAdapter`的总体过程](#3.2. 再看RequestMappingHandlerAdapter的总体过程)
      • [3.2.1. RequestParamMethodArgumentResolver](#3.2.1. RequestParamMethodArgumentResolver)
      • [3.2.2. 反射调用 Controller 的方法](#3.2.2. 反射调用 Controller 的方法)
      • [3.2.3. RequestResponseBodyMethodProcessor](#3.2.3. RequestResponseBodyMethodProcessor)
  • [4. 总结](#4. 总结)

本文以"最经典"的情况分析了 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(返回值处理器)
相关推荐
Coder码匠22 分钟前
Dockerfile 优化实践:从 400MB 到 80MB
java·spring boot
qq_124987075324 分钟前
基于SpringCloud的分布式演唱会抢票系统(源码+论文+部署+安装)
分布式·spring·spring cloud·毕业设计·计算机毕业设计
李慕婉学姐8 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆9 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin10 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model200510 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉10 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国10 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_9418824810 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈11 小时前
两天开发完成智能体平台
java·spring·go