SpringMVC工作原理之参数解析

article/2025/9/14 1:42:27

前面分析到 SpringMVC工作原理之处理映射[HandlerMapping] ,由映射处理器(HandlerMapping) 解析出对应的 handler。接着 SpringMVC工作原理之适配器[HandlerAdapter] 描述了 handler 是怎么匹配到合适的适配器,进行 handler 对应方法的执行。其他几种适配器还好,但是 RequestMappingHandlerAdapter 适配器对应接下来的参数解析及绑定并执行并不是那么简单,因此本篇笔记主要分析 RequestMappingHandlerAdapter 适配器解析对应 handler 的执行流程。
本篇笔记主要分析SpringMVC 5.1.1 这个版本。

SpringMVC运行流程

RequestMappingHandlerAdapter 大概解析流程如下

RequestMappingHandlerAdapter解析流程

1 了解在前面

在开始下面的具体源码分析前,我们需要了解一些相关的类和接口

1.1 HandlerMethod

在开始记录方法执行流程前,必须要先说下记录方法的对象 HandlerMethodHandlerMethod 及子类主要用于封装方法调用相关信息。简单理解为保持方法信息的 pojo 类。

HandlerMethod及其子类.png

分析下各个类的功能及职责:

  • HandlerMethod 封装方法定义相关的信息 (如类、方法、参数等)
  • InvocableHandlerMethod 参数准备委托 HandlerMethodArgumentResolver 进行具体的解析
  • ServletInvocableHandlerMethod 添加返回值处理职责,ResponseStatus 处理

在容器初始化的时候,RequestMappingHandlerMapping 映射处理器就将 @RequestMapping 描述的方法以 RequestMappingInfo 为 key,HandlerMethod 为 value 放进自己的缓存 。至如 HandlerMethod 内部后面是怎么进行对应方法上的参数解析及绑定到后来的方法执行等等,咱们接下来会详细讲解。

1.2 参数解析器(HandlerMethodArgumentResolver)和返回值的解析器(HandlerMethodReturnValueHandler)

在分析源码之前,首先让我们来看下SpringMVC中两个重要的接口,两个接口都是在 3.1 版本后添加的。

  • 处理方法参数的解析器接口

  • 处理方法调用返回值的解析器接口

两个接口分别有两个方法,一个用来查看该解析器是否支持该参数的解析,第二个方法用来对参数进行解析。

1.3 默认解析器的注入

在容器初始话的时候,初始化 RequestMappingHandlerAdapter 适配器的时候会将默认的参数解析器都注入进缓存中。

加载默认的参数解析器(ArgumentResolvers),绑定到 RequestMappingHandlerAdapter 适配器的 argumentResolvers 属性上。
加载默认的返回值解析器(ReturnValueHandlers),绑定到 RequestMappingHandlerAdapter 适配器的 returnValueHandlers 属性上。

下面我们来简单的看下都有哪些默认解析器

  • 默认注入的参数解析器

  • 默认注入的返回值解析器

2 解析过程流程

2.1 解析器的绑定及匹配

接着 RequestMappingHandlerAdapter 适配器的 handleInternal(..) 方法往下说,在 handleInternal(..) 方法中主要检查是否需要同步执行接下来对方法的操作,内部调用 invokeHandlerMethod(..) 方法。

该方法内部就方法执行流程大致可以分为以上标注的 6 步:

①. 对应 WebDataBinderFactory 工厂类的创建,因里面涉及到的东西有点多,将放在下面参数值类型转换部分详细解说。
②. 根据该 HandlerMethod 创建对应的 ServletInvocableHandlerMethod 对象。
③. 将注入到缓存的参数解析器绑定到创建的 ServletInvocableHandlerMethod 对象上。
④. 将注入缓存的返回值解析器绑定到创建的 ServletInvocableHandlerMethod 对象上。
⑤. 将上面创建的 WebDataBinderFactory 工厂类对象绑定到创建的 ServletInvocableHandlerMethod 对象上。
⑥. 执行 ServletInvocableHandlerMethodinvokeAndHandle(...) 方法。

总结:RequestMappingHandlerAdapter 在内部对于每个请求,都会实例化一个 ServletInvocableHandlerMethod 进行处理。

ServletInvocableHandlerMethod 内部会分别对请求跟响应进行处理。

进入执行请求对应方法里面看看流程

接下来就是请求参数解析器和返回值解析器上场的时候了。

①. ServletInvocableHandlerMethod 类在处理参数的时候,会使用自己绑定的参数解析器,参数解析器记录在属性argumentResolvers (这个属性是它的父类 InvocableHandlerMethod中定义的),argumentResolvers 属性是一个 HandlerMethodArgumentResolverComposite 类(这里使用了组合模式的一种变形),这个类是实现了 HandlerMethodArgumentResolver 接口的类,实现了该类里面的两个接口。同时里面有记录所有参数解析器的 List 集合,有缓存 MethodParameter 与解析器对应关系的 Map 集合。

②. ServletInvocableHandlerMethod 类在处理返回值的时候,会使用自身绑定的返回值解析器,该解析器记录在属性 returnValueHandlers (自身属性),returnValueHandlers 属性是一个 HandlerMethodReturnValueHandlerComposite 类(这里使用了组合模式的一种变形),这个类实现了 HandlerMethodReturnValueHandler 接口,实现了该接口里面的两个方法。同时里面有记录所有返回值解析器的 List 集合。

2.2 参数解析器内部解析流程

因为解析器太多,这里只能抽其中一个来了解下参数解析器内部实现解析的逻辑,选个最常用的解析器 RequestParamMethodArgumentResolver,他是用来解析 @RequestParam 注解的参数。RequestParamMethodArgumentResolver 继承自 AbstractNamedValueMethodArgumentResolver,而 AbstractNamedValueMethodArgumentResolver 抽象类实现了 HandlerMethodArgumentResolver 接口。

首先来看下其支持解析的参数种类

再来看下其解析参数的过程

参数解析的过程可以分为三个部分:参数名字解析、参数值获取、参数值类型转换

(1). 参数名字解析

NamedValueInfo 是该抽象解析器定义的一个内部类,有三个属性记录形参上的修饰,分别是 namerequireddefaultValue,分别记录形参名字、形参是否必须、形参默认值。

咱们来看下 RequestParamMethodArgumentResolver 子类是怎么实现 createNamedValueInfo(..) 这个方法的。

很明显返回的是 RequestParamNamedValueInfo 对象,RequestParamNamedValueInfo 类是该解析类里面的一个内部类,继承自 NamedValueInfo,构建方法里面将传进去的 RequestParamnamerequireddefaultValue 分别记录到创建的 RequestParamNamedValueInfo 对象的属性上。

通过后面的 updateNameValueInfo(..) 方法检查一遍,当 @RequestParam 注解的 namevalue 属性为空时,会自动以形参的名字作为 name

(2). 参数值获取

resolveName(...) 抽象类的抽象方法,具体由其子类实现,下面我们来看下 RequestParamMethodArgumentResolver 解析类是怎么实现的吧。

上面分别实现了可变请求和不可变请求对于根据 name 取值的方式。

(3). 参数值类型转换

从上面源码可以看出,通过自身绑定的 binderFactory 创建出 WebDataBinder 对象,通过创建出来的 WebDataBinder 对象来进行数据转换。
那么接下来的分析就有条理了,分为三个部分:WebDataBinderFactory 属性对象的创建及绑定、WebDataBinderFactory 属性对象内部执行 createBinder(...) 方法创建出 WebDataBinder 对象的具体逻辑、 WebDataBinder 进行数据类型转换的具体逻辑。

(3.1) WebDataBinderFactory 属性对象的创建及绑定

前面说到在 RequestMappingHandlerAdapter 适配器中执行 invokeHandlerMethod(...) 方法,通过 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); 方法创建 WebDataBinderFactory 对象,并将其绑定在创建的 ServletInvocableHandlerMethod 对象上。

这里的 this.webBindingInitializer 属性其实就是一个 ConfigurableWebBindingInitializer 对象,即在 <mvc:annotation-driven /> 时默认注册的。即包含一些解析参数需要的 MessageCodesResolverBindingErrorProcessorValidatorConversionServicePropertyEditorRegistrar[]

(3.2) WebDataBinderFactory 对象内部执行 createBinder(...) 方法创建出 WebDataBinder 对象的具体逻辑

首先来看下 WebDataBinderFactory 接口的实现类

再来看 createBinder(...) 方法

1 newWebDataBinder 接口实现类,依照自身实现类为准,从 (3.1) 看出这里的 this 对象是 ServletRequestDataBinderFactory 对象,new 出来的 WebDataBinder 接口实现类应该是 ExtendedServletRequestDataBinder 类对象。

2 对 WebDataBinder 对象进行一些初始化,this.initializer 属性是在上面 (3.1) 绑定进来的 ConfigurableWebBindingInitializer 对象。

从执行方法里面可以看出设置一些我们在解析参数时用到的转换器和验证器到 WebDataBinder 对象上。

3 自身初始化 WebDataBinder 的方法

从上面 isBinderMethodApplicable(..) 匹配符合该参数转换的 @initBinder 注解修饰的方法逻辑可以看出,以后在 Controller 里面写 @initBinder 注解修饰的方法,尽量指定 value 属性字段,以免每个参数解析都执行不必要的 @initBinder 注解修饰的方法。

(3.3) WebDataBinder 进行数据类型转换的具体逻辑,执行convertIfNecessary(...) 方法

数据转换这块很复杂,我目前的能力只能做潜在的分析。因为 WebDataBinder 继承自 DataBinder,又因为 DataBinder 实现了PropertyEditorRegistryTypeConverter 接口,所以该类具有注入自定义编辑器和转换数据的能力。
数据的转换最终交给 TypeConverterDelegate 类进行转换

从上面可以看出,先匹对自定义的编辑器进行数据转换,没有合适的编辑器则匹配对应的转换器进行数据转换。
再来看下第 3 步自定义编辑器里面是怎么来转换数据的

2.3 返回值析器内部解析流程

前面说到返回值处理器记录在 ServletInvocableHandlerMethod 绑定的 returnValueHandlers 属性上,returnValueHandlers 属性是一个 HandlerMethodReturnValueHandlerComposite 类,这个类是一种组合模式的变形,他也实现了 HandlerMethodReturnValueHandler 接口,并且该类里面有 returnValueHandlers 属性是 List 集合属性,缓存了所有的返回值处理器。不清楚的可以看上面的 2.1 解析器的绑定及匹配

由于返回值处理器也比较多,所以这里也选取一个最常用的 ViewNameMethodReturnValueHandler 返回值解析器看下内部实现原理。首先他肯定实现了 HandlerMethodReturnValueHandler 接口,并实现了该接口里面的两个方法。

其他相关文章

SpringMVC入门笔记
SpringMVC工作原理之处理映射[HandlerMapping]
SpringMVC工作原理之适配器[HandlerAdapter]
SpringMVC工作原理之参数解析
SpringMVC之自定义参数解析
SpringMVC工作原理之视图解析及自定义
SpingMVC之<mvc:annotation-driven/>标签


http://chatgpt.dhexx.cn/article/hW8hg2qx.shtml

相关文章

16.springmvc工作原理分析

springmvc 如何做URL映射关系 1.SpringIOC容器加载时开始遍历所有的bean对象 判断 bean对象 类上是否有加上 Controller注解,如果类上有加该注解的话 则该类就是为我们控制类&#xff1b; 2.在容器初始化时会建立所有url和controller的对应关系&#xff0c;利用java反射机制…

SpringMVC工作原理及其流程

本文介绍SpringMVC的基本原理,对于一个浏览器请求,SpringMVC的处理流程。 SpringMVC主要包含一下组件 DispatcherServlet-前端控制器HandlerMapping-处理器映射Controller-控制器ViewResolver-视图解析器View-视图Spring的请求流程 SpringMVC的核心在于其请求流程,这是使用…

阿里云YUM源配置

文章目录 阿里云YUM源配置1.备份原有yum源2.根据自己系统下载yum源3.重新加载yum0x00. 阿里云YUM源配置 今天&#xff0c;打开我的Centos7系统&#xff0c;美滋滋要搭建一波LAMP环境。一把梭哈。 yum -y install httpd mariadb mariadb-server php php-mysql 奈何&#xff0c;…

Linux学习-20-yum介绍,yum源配置

7.8 yum介绍&#xff0c;yum源配置 使用 SRPM 源码包和 RPM 二进制包安装软件&#xff0c;这两种方法都比较繁琐&#xff0c;需要手动解决包之间具有依赖性的问题&#xff0c;尤其是库文件依赖&#xff0c;需要自行去 http://www.rpmfind.net 网站上查找相关的 RPM 包。 7.8.…

yum源配置及相关命令

1.yum概述 yum是软件管理仓库&#xff0c;可以完成安装&#xff0c;卸载&#xff0c;自动升级rpm包等任务&#xff0c;能够自动查找并解决rpm包之间的依赖关系&#xff0c;而无需管理员手工安装每个rpm包 2.本地源和网络源 本地源:比如说光盘里面一般会附带一些软件&#xff0c…

redhat yum源配置-已成功

提示&#xff1a;几分钟就搞定&#xff0c;替大家避坑了。 yum源配置 redhat使用yum源时不成功&#xff0c;这是因为使用 redhat 自带的 yum源要付费&#xff0c;所以需要自己重新生成 yum源&#xff0c;Redhat7 和Centos7是完全一样的&#xff0c;可是安装完Redhat7以后&#…

Openstack实验之yum源配置

1.实验目的 对于企业的Openstack私有云&#xff0c;出于对安全和某些因素的安全考虑&#xff0c;有些服务器无法访问公网&#xff0c;导致服务器无法更新某些RPM包&#xff0c;同时内部常有Openstack新特性开发需求&#xff0c;版本的维护与升级&#xff0c;因此非常有必要构建…

CentOS6.5 yum源配置

编辑配置文件 vim /etc/yum.repos.d/CentOS-Base.repo将以下内容复制到配置文件中 [base] nameCentOS-6 failovermethodpriority baseurlhttp://mirrors.aliyun.com/centos-vault/6.5/os/x86_64/ gpgcheck0生成缓存 yum clean all#清除全部 yum makecache#生成缓存也可以 c…

阿里云的yum源配置

首先&#xff0c;将目录切换至/etc/yum.repos.d&#xff0c;这个是需要更换的yum源&#xff0c;一般系统都自带有yum源&#xff0c;但是下载速度很慢&#xff0c;所以需要将yum源换为国内的yum源&#xff0c; 这里一般有两种方法&#xff1a; 1、首先使用wget 下载阿里云的yum源…

FTP - YUM 源配置

** Ftp yum源配置 一、 环境需要 1、2台centos A和B 2、配置两台主机的ip 3、关闭防火墙(2台) [rootlocalhost ~]# systemctl stop firewalld[rootlocalhost ~]# systemctl disable firewalld关闭selinux [rootlocalhost ~]# vim /etc/sysconfig/selinux把SELINUXenforcing改…

yum源配置,这一篇就够了!(包括本地,网络,本地共享yum源)

服务器yum源配置 文章目录 1. 引言1.1 什么是yum源1.2 为什么要搭建内网yum源1.3 准备工作 2. yum源搭建2.1 网络yum源配置2.1.1 yum仓库配置2.1.2 更新yum源2.1.3centos yum源一键配置命令2.1.4 其他yum源参考 2.2 本机单机yum源配置2.2.1 iso镜像获取并上传到服务器2.2.2 rep…

Linux下局域网yum源配置

文章目录 一 需求二 搭建环境准备三 服务端1 创建镜像存放目录与挂载目录2 上传centos7镜像3 对镜像文件进行挂载4 配置本地yum源5 对挂载点建立软链接6 安装http服务7 浏览器验证http服务是否正常启动 四 客户端1 修改yum配置文件2 查看yum源 一 需求 企业内部服务器出于安全…

yum源配置教程

环境&#xff1a;Centos7系统、Centos7镜像文件&#xff08;下文中提到的光盘&#xff09;、能连接互联网 yum是Linux平台下的一个包管理工具&#xff0c;全称叫做Yellow dog Updater,Modified&#xff0c;Shell前端软件包管理器。基于RPM包管理&#xff0c;能够从指定的服务器…

本地Yum源配置

Yum源访问方式有三种&#xff0c;分别是互联网yum源、局域网yum源、本地yum源 yum可以自动处理依赖关系&#xff0c;并且一次安装所有依赖包&#xff0c;无须繁琐地一次次下载、安装。 配置本地yum源之前需要通过Xftp连接上传操作系统的CentOS-7-x86_64-DVD-2009.iso镜像文件…

Yum源配置

一、使用网络yum源 1、百度搜索网易mirror&#xff1b; 2、找到Centos帮助文档&#xff1b; 3、备份默认yum源&#xff1b; 4、复制repo文件源地址&#xff1b; 5、Centos中使用wget命令下载repo文件&#xff1b; 6、清除yum源缓存&#xff1b; # yum clean all 7、生成新的y…

yum 源配置

CentOS6国内常用yum源站点 原创 WalkingCloud212022-03-01 16:16:46©著作权 文章标签centossed缓存文章分类其它其它阅读数709 ​1、腾讯云镜像站​ ​ ​ ​​ ​​ ​1)替换之前先备份旧配置​ ​mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Ba…

如何配置YUM源

如何配置YUM源 一、YUM简介二、YUM源的配置与更新 一、YUM简介 YUM&#xff08;yellowdong updater modified&#xff09;是一个功能完善、易于使用的软件维护工具&#xff0c;它可以根据用户的要求分析出所需软件包及其相关的依赖关系&#xff0c;然后自动从服务器&#xff0…

yum源的三种配置方式

Linux系统yum源的三种配置方式 一.yum简述 yum是“Yellow dog Updater, Modified”的缩写&#xff0c;是一个软件包管理器当我们使用Linux操作系统时&#xff0c;我们绕不开的还是如何去下载软件&#xff0c;源码软件包编译无疑是一件费劲的事情&#xff0c;花时间&#xff0c…

最速下降法 理论证明

原作者链接&#xff1a;梯度下降法与最速下降&#xff08;凸优化方法&#xff09; 另一种证明最优步长公式的方式&#xff1a; 注意&#xff1a;表示目标搜索方向向量&#xff0c;在求最优步长时表示为点处梯度的反向向量&#xff0c;和在下面的证明表示的都是学习率&#xf…

最优化方法-最速下降法

最速下降法基本介绍 在解决无约束问题时&#xff0c;经常用到的一类算法是最速下降法&#xff0c;在求解机器学习 算法的模型参数&#xff0c;即无约束优化问题时&#xff0c;梯度下降是最常采用的方法之一&#xff0c;在求 解损失函数的最小值时&#xff0c;可以通过梯度下…