spring5源码篇(12)——spring-mvc请求流程

news2024/9/27 9:28:37

spring-framework 版本:v5.3.19

文章目录

  • 一、请求流程
    • 1、处理器映射器
      • 1.1、 RequestMappingHandlerMapping
      • 1.2、获取对应的映射方法
      • 1.3、添加拦截器
    • 2、获取合适的处理器适配器
    • 3、通过处理器适配器执行处理器方法
      • 3.1、拦截器的前置后置
      • 3.2、处理器的执行
        • 3.2.1 参数解析器解析参数和执行处理器方法
        • 3.2.2 结果处理器处理结果
        • 3.2.3 消息转化器
    • 4、视图解析器
  • 二、请求流程中的一些问题
  • 1、各种组件如处理器映射器,处理器适配器,视图解析器等是如何注入到spring容器的?
  • 2、RequestMappingInfoHandlerMapping 处理器映射器中维护的映射map (即MapingRegister) 是如何初始化的?
  • 3、处理器映射器中的拦截器是如何添加的?
  • 4、处理器适配器的参数解析器和结果处理器是如何来的?
  • 5、参数解析器/结果处理器中的消息转化器是如何来的?

一、请求流程

总体流程在 DispatchServelt#doDispatch 方法
在这里插入图片描述

1、处理器映射器

首先会获取根据url去映射对应的处理器(即接口执行方法)
看到对应的 getHandler 方法
在这里插入图片描述
为方便阅读,进入debug。可以看到springmvc默认为我们注册了三个handlerMapping。

springMvc中的各个组件如处理器映射器,处理器适配器,视图解析器等是如何注入到容器的,先暂时不看,第二部分在看(问题1)。

1.1、 RequestMappingHandlerMapping

而其中我们最常用的一个就是RequestMappingHandlerMapping,所以这里只看这个类的 getHandler 方法(其实也是其抽象父类的方法)。
在这里插入图片描述

1.2、获取对应的映射方法

getHandlerInternal 方法入手,看看是如何把一个请求映射到对应的方法的。
在这里插入图片描述
这里首先会从 mappingRegister 中去找可以根据url直接得到的映射(即没有替换符),如果找不到再去所有注册的映射中找,然后返回一个最匹配的映射对应的处理器。

mappingRegister 可以简单的理解成 Map<url,handler>。实际上,为提供效率一共维护了3个map
在这里插入图片描述
这些map是如何初始化的,第二部分再讲(问题2)。

至于是如何匹配这些映射的,从 addMatchingMappings 入手
在这里插入图片描述
这里其实就是把匹配逻辑抽象成一个个condition,如果满足所有 condition 说明这是一个可用的处理器。注意,仅是可用而已,并不一定会用这个处理器。因为可能同时会匹配到多个可用的处理器,但是最终只会返回最匹配的那一个。

1.3、添加拦截器

在前面的总体流程中注释到,获取处理器的时候,返回的是一个处理器链。因为可能会配置有拦截器,而拦截器的添加从 getHandlerExecutionChain 入手。
在这里插入图片描述
可以看到,就只是遍历当前 handlerMapping 所添加的所有拦截器,若匹配,则将该拦截器添加到处理器链中而已。至于 handlerMapping 的拦截器是如何添加的,第二部分再讲(问题3)。

2、获取合适的处理器适配器

在这里插入图片描述
Spring MVC可能会有多种类型的处理器,例如控制器(Controller)、RESTful控制器等。处理器适配器负责选择并调用合适的处理器来处理请求。这一步就是去获取一个合适的处理器适配器,其实就是一个简单遍历获取,在spring mvc 默认提供的几种适配器中,最常用的还是 RequestMappingHandlerAdapter

3、通过处理器适配器执行处理器方法

3.1、拦截器的前置后置

在正式看处理器之前,顺便提一嘴拦截器的执行。
在执行实际业务方法之前会先执行处理器链中拦截器前置方法。同理,执行完业务方法后会执行处理器链中拦截器的后置方法。
在这里插入图片描述
拦截器的执行就是一个遍历,就不上代码了。

3.2、处理器的执行

ha.handle 入手
在这里插入图片描述
不管是哪种适配器,最终都会依次通过 参数解析器、处理器、结果处理器 将方法返回值封装成 ModelAndView 对象。

3.2.1 参数解析器解析参数和执行处理器方法

从 invokeForRequest 入手
在这里插入图片描述
处理器方法的执行就是反射实现的,没啥好看的。主要看参数解析器是如何解析参数的。
在这里插入图片描述
InvocableHandlerMethod 中维护了名为 resolvers 的 HandlerMethodArgumentResolverComposite 对象(多个参数解析器的封装),并且这个变量的值是处理器适配器传过来的。至于处理器适配器的参数解析器是哪来的,先暂时不看,后面第二部分再看(问题4)。这里只需知道参数解析器是在这里解析的以及值是处理器适配器传过来的就可以了。

3.2.2 结果处理器处理结果

从 returnValueHandlers.handleReturnValue 入手
在这里插入图片描述
**跟参数解析器维护的复合对象一样,也维护了一个名为 returnValueHandlers 的 HandlerMethodReturnValueHandlerComposite 复合对象,并且这个变量的值也是处理器适配器传过来的。**至于处理器适配器的结果处理器是哪来的,也先暂时不看。

一般来说参数解析器的命名为 xxxMethodArgumentResolver 而结果处理器的命名为 xxxMethodReturnValueHandler。但是如果即是参数解析器又是结果处理器的命名就会xxxMethodProcessor。而我们常用的 RequestResponseBodyMethodProcessor 就是这种类型。
在这里插入图片描述

3.2.3 消息转化器

首先并不是所有的参数解析器或者结果处理器都会用到消息转化器。,但至少我们最常用的 **RequestResponseBodyMethodProcessor 无论是解析参数还是处理结果,都会用到消息转化器。**对应的方法分别是 readWithMessageConverters,writeWithMessageConverters。并且write是直接写到 http 的response,这也意味着 @ResponseBody 不需要通过视图解析器解析渲染视图。
在这里插入图片描述

在 RequestResponseBodyMethodProcessor 中无论是read还是write,都会去遍历参数解析器/结果处理器中维护的消息转化器列表。至于 参数解析器/结果处理器的消息转化器列表是哪里来的,也先暂时不看,后面在看(问题5)。

4、视图解析器

试想这么一个接口,没有 @ResponseBody 并且返回值是一个字符串。

如果有 @ResponseBody 注解,ModelAndView为null,无需解析渲染视图。
在这里插入图片描述
在我们配置如下的视图解析器时会访问到servlet容器下的mv.html页面。
在这里插入图片描述
从字符串到返回的具体页面,这正是视图解析器所做的事情。

关于视图解析器,从 processDispatchResult 入手
在这里插入图片描述
解析:如果 ModelAndView 有视图名(在上面的例子中视图名就是方法返回的字符串)就会调用视图解析器去解析视图名得到一个视图 View 对象,反之就从 ModelAndView 中直接获取 View 对象。总之,不管怎样,这里一定要有 View 对象,没有就报错。
渲染:然后再调用上一步得到的 View 对象 render 方法并将 ModelAndView 里的 Model 数据传入,从而将数据渲染带视图上(如:jsp)。最后将渲染后的结果返回至前端。


至此一个完整的请求流程就看完了。为更形象记忆 spring mvc 各组件之间的关系,这里附上一张网图
在这里插入图片描述

二、请求流程中的一些问题

1、各种组件如处理器映射器,处理器适配器,视图解析器等是如何注入到spring容器的?

答:@EnableWebMvc注解(相当于xml配置: <mvc:annotation-driven/>)。
在这里插入图片描述
@EnableWebMvc 引入了 DelegatingWebMvcConfiguration,而这个类中就默认注入了 spring mvc 的各种组件。
比如:
在这里插入图片描述

2、RequestMappingInfoHandlerMapping 处理器映射器中维护的映射map (即MapingRegister) 是如何初始化的?

答:在 RequestMappingInfoHandlerMapping bean生命周期的 afterPropertiesSet。
在这里插入图片描述

3、处理器映射器中的拦截器是如何添加的?

答:以 RequestMappingInfoHandlerMapping 为例,在 DelegatingWebMvcConfiguration 注入处理器映射器的时就同时会去set拦截器。
在这里插入图片描述
其中 getInterceptors 代码如下
在这里插入图片描述
说白了就是 getInterceptors 方法,会依次调用所有的 WebMvcConfigurer.addInteceptors 方法将自定义配置的拦截器添加到处理器映射器中的 InterceptorRegistry。之后处理器映射器在映射处理器时,将其中匹配的拦截器添加到处理链,进而实现拦截器的效果。

正是因为自动注入的原理,所以我们平时配置spring mvc时只需注入一个实现 WebMvcConfigurer 接口的类。

但其实截至目前为止添加的还只是一个原始版本的拦截器,真正使用的拦截器是适配后的版本。
适配的时机是在处理器映射器生命周期的 setApplicationContext 方法。(最后会调用到 initApplicationContext)
在这里插入图片描述

4、处理器适配器的参数解析器和结果处理器是如何来的?

答:在 RequestMappingHandlerAdapter bean生命周期的 afterPropertiesSet。

在这里插入图片描述
具体添加了哪些参数解析器,结果处理器就不细看了,太多了…

5、参数解析器/结果处理器中的消息转化器是如何来的?

答:来自处理器适配器,而处理器适配器的消息转化器来自 WebMvcConfigurer 配置或者默认配置。

如下图:
(参数解析器/结果处理器中的消息转化器来自处理器适配器)
在这里插入图片描述
(适配器的来自 WebMvcConfigurer 配置或者默认配置)
在这里插入图片描述

至于this.configurers.configureMessageConverters(converters);
首先configurers在前面第三个问题已经看过了,就是自动注入的 WebMvcConfigurer 总和。所以这句总的来说就是依次调用所有的 WebMvcConfigurer.configureMessageConverters 方法将自定义配置的消息添加到处理器适配器中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/805333.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity 性能优化二:内存问题

目录 策略导致的内存问题 GFX内存 纹理资源 压缩格式 Mipmap 网格资源 Read/Write 顶点数据 骨骼 静态合批 Shader资源 Reserved Memory RenderTexture 动画资源 音频资源 字体资源 粒子系统资源 Mono堆内存 策略导致的内存问题 1. Assetbundle 打包的时候…

【C++】C++ STL标准模板库知识点总结(秋招篇)

文章目录 前言STL的六大组件是&#xff1f;容器(container) 算法(algorithm) 迭代器(iterator) 三者的关系&#xff1f;容器分为几种&#xff1f;分别有哪些&#xff1f;关联性容器和非关联性容器有什么区别&#xff1f;Vector容器是怎么调整大小的&#xff1f;&#xff08;内存…

VirtualEnv 20.24.0 发布

导读VirtualEnv 20.24.0 现已发布&#xff0c;VirtualEnv 用于在一台机器上创建多个独立的 Python 运行环境&#xff0c;可隔离项目之间的第三方包依赖&#xff0c;为部署应用提供方便&#xff0c;把开发环境的虚拟环境打包到生产环境即可&#xff0c;不需要在服务器上再折腾一…

RAM明明断电会丢失数据,为什么初始化的全局变量存储在RAM?详细分析程序的存储

前言 &#xff08;1&#xff09;之前因为一个字符指针和字符数组指针引发的bug&#xff0c;折磨了我一个下午才发现问题。之后我就打算研究一下系统是如何发现野指针乱访问问题。后面就一直深入到微机系统中的内存管理了。 &#xff08;2&#xff09;这些其实都是基础知识&…

SpringBoot房屋租赁系统【附ppt|万字文档(LW)和搭建文档】

主要功能 前台登录&#xff1a; ①首页&#xff1a;公告信息、房屋信息展示、查看更多等 ②房屋信息、房屋类型、我要当房主、公告信息、留言反馈等 ③个人中心&#xff1a;可以查看自己的信息、更新图片、更新信息、退出登录、我的收藏 后台登录&#xff1a; ①首页、个人中心…

Day 69-70:矩阵分解

代码&#xff1a; package dl;import java.io.*; import java.util.Random;/** Matrix factorization for recommender systems.*/public class MatrixFactorization {/*** Used to generate random numbers.*/Random rand new Random();/*** Number of users.*/int numUsers…

使用贝叶斯算法完成文档分类问题

贝叶斯原理 贝叶斯原理&#xff08;Bayes theorem&#xff09;是一种用于计算条件概率的数学公式。它是以18世纪英国数学家托马斯贝叶斯&#xff08;Thomas Bayes&#xff09;的名字命名的。贝叶斯原理表达了在已知某个事件发生的情况下&#xff0c;另一个事件发生的概率。具体…

【Golang系统开发】搜索引擎(1) 如何快速判断网页是否已经被爬取

文章目录 1. 写在前面2. 数组存储3. 位图存储3.1 位图简介3.2 链表法3.3 开放寻址法 1. 写在前面 在实际工作中&#xff0c;我们经常需要判断一个对象是否存在&#xff0c;比如判断用户注册登陆时候&#xff0c;需要判断用户是否存在&#xff0c;再比如搜索引擎中的爬虫&#x…

大数据面试题之Elasticsearch:每日三题(七)

大数据面试题之Elasticsearch:每日三题 1.Elasticsearch索引文档的流程&#xff1f;2.Elasticsearch更新和删除文档的流程&#xff1f;3.Elasticsearch搜索的流程&#xff1f; 1.Elasticsearch索引文档的流程&#xff1f; 协调节点默认使用文档ID参与计算(也支持通过routing)&a…

【UE4】给角色添加脚步声

步骤&#xff1a; 1. 导入一个脚步声音频文件&#xff08;.wav格式&#xff09; 2. 打开角色蓝图&#xff0c;这里以第三人称角色模板蓝图“ThirdPersonCharacter”为例&#xff0c;在事件图表中添加一个生成音效的自定义事件。 3. 打开动画序列“ThirdPersonRun” 找到小白人…

Python编程——while循环嵌套讲解(附案例)

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 本文专栏&#xff1a;Python专栏 专栏介绍&#xff1a;本专栏为免费专栏&#xff0c;并且会持续更新python基础知识&#xff0c;欢迎各位订阅关注。 目录 一、while嵌套的语法 二、注意事项 三、while嵌套循…

【Java】分支结构习题

【Java】分支结构 文章目录 【Java】分支结构题1 &#xff1a;数字9 出现的次数题2 &#xff1a;计算1/1-1/21/3-1/41/5 …… 1/99 - 1/100 的值。题3 &#xff1a;猜数字题4 &#xff1a;牛客BC110 X图案题5 &#xff1a;输出一个整数的每一位题6 &#xff1a; 模拟三次密码输…

统信UOS安装mysql数据库(mariadb)-统信UOS安装JDK-统信UOS安装nginx(附安装包)

统信UOS离线全套安装教程&#xff08;手把手教程&#xff09; 银河麒麟的各种离线全套安装教程&#xff1a; https://blog.csdn.net/ACCPluzhiqi/article/details/131988147 1.统信UOS桌面系统安装mysql&#xff08;mariadb&#xff09; 2.统信UOS桌面系统安装JDK 3.统信UOS桌…

CAN学习笔记3:STM32 CAN控制器介绍

STM32 CAN控制器 1 概述 STM32 CAN控制器&#xff08;bxCAN&#xff09;&#xff0c;支持CAN 2.0A 和 CAN 2.0B Active版本协议。CAN 2.0A 只能处理标准数据帧且扩展帧的内容会识别错误&#xff0c;而CAN 2.0B Active 可以处理标准数据帧和扩展数据帧。 2 bxCAN 特性 波特率…

【JavaWeb】正则表达式

&#x1f384;欢迎来到边境矢梦的csdn博文&#xff0c;本文主要讲解Java 中正则表达式 的相关知识&#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一下&#x1faf0;&#x1faf0;&am…

Metabase RCE漏洞复现(CVE-2023-38646)

0x01 产品简介 Metabase是一个开源的数据分析和可视化工具&#xff0c;它可以帮助用户轻松地连接到各种数据源&#xff0c;包括数据库、云服务和API&#xff0c;然后使用直观的界面进行数据查询、分析和可视化。 0x02 漏洞概述 未经身份认证的远程攻击者利用该漏洞可以在服务器…

【C语言趣味教程】(4) 变量:代码注释 | 变量的声明 | 初始化与赋值 | 变量的命名 | 关键字 | 标识符 | 变量名的命名规范

&#x1f517; 《C语言趣味教程》&#x1f448; 猛戳订阅&#xff01;&#xff01;&#xff01; Ⅰ. 代码注释&#xff08;Comment&#xff09; 0x00 引入&#xff1a;注释的作用 "程序员最讨厌两种人&#xff1a;一种是不写注释的人&#xff0c;一种是让我写注释的人。…

如何用DHTMLX组件为Web应用创建甘特图?(一)

dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的所有需求&#xff0c;是最完善的甘特图图表库。甘特图仍然是项目管理应用程序中最需要的工具之一&#xff0c;DHTMLX Gantt组件提供了能提升研发甘特图功能所需的重要工具。 在这篇…

【深度学习】InST,Inversion-Based Style Transfer with Diffusion Models,论文

代码&#xff1a;https://github.com/zyxElsa/InST 论文&#xff1a;https://arxiv.org/abs/2211.13203 文章目录 AbstractIntroductionRelated WorkImage style transferText-to-image synthesisInversion of diffusion models MethodOverview ExperimentsComparison with Sty…

我的第一个后端项目(环境搭建,Springboot项目,运行,接口验证)

一. 安装Java开发工具包&#xff08;JDK&#xff09;&#xff1a; 访问Java Software | OracleOracle官方网站&#xff0c;下载适合你操作系统的最新版本的JDK。安装JDK并设置好JAVA_HOME环境变量。 二. 安装集成开发环境&#xff08;IDE&#xff09;&#xff1a; 推荐使用In…