SpringMVC底层——请求参数处理流程描述

在DispatcherServlet.java的doDispatch方法中,springmvc通过handlermapping里面找哪个handler能处理请求,handler封装了目标方法的信息,

mappedHandler = getHandler(processedRequest);

然后为当前的handler找到一个适配器HandlerAdapter,寻找的过程为:在DispatcherServlet.java的getHandlerAdapter方法中,挨个匹配,判断当前adapter是否支持当前handler,判断方法为只要handler是handlerMethod类型就生效,就支持

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
if (this.handlerAdapters != null) {
    for (HandlerAdapter adapter : this.handlerAdapters) {
        if (adapter.supports(handler)) {
            return adapter;
            }
    }
}

找到适配器以后判断当前请求是不是”GET”方法以及”HEAD”,”HEAD”不是服务器真正处理的

适配器 HandlerAdapter把(目标方法、request、response)传入handle执行目标方法

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

怎么执行目标方法:

  • 先得到handler
return this.handler;
  • 再进入内部处理细节RequestMappingHandlerAdapter.java,调用的invokeHandlerMethod就是 *执行目标方法
mav = invokeHandlerMethod(request,response,handlerMethod);
  • 在RequestMappingHandlerAdapter.java的invokeHandlerMethod方法中,
  • 为invocableMethod方法设置 参数解析器argumentResolvers,参数解析器确定将要执行的目标方法的每一个参数的值是什么
    • 当前解析器是否支持解析这种参数
    • 支持就调用 resolveArgument
  • 为invocableMethod方法设置 返回值处理器returnValueHandlers
  • 把26个argumentResolvers和15个returnValueHandlers都放入目标方法包装的ServletInvocableHandlerMethod中
  • 然后真正执行目标方法的语句
invocableMethod.invokeAndHandle(WebRequest,mavContainer);
  • 在ServletInvocableHandlerMethod.java的invokeAndHandle方法中,执行了controller
Object returnValue = invokeForRequest(webRequest,mavContainer,proviedArgs);
+ step into 进入InvocableHandlerMethod.java, **确定目标方法每一个参数的值**
Object[] agrs = getMethodArgumentValues(request,mavContainer,providerArgs)
  * 在InvocableHandlerMethod.java的getMethodArgumentValues方法中,先获取方法所有的参数声明(详细信息)。
MethodParameter[] parameters = getMethodParameters();
  * 判断参数是否为空,为空则无需确定任何值直接返回;
if (ObjectUtils.isEmpty(parameters)) {
    return EMPTY_ARGS;
}

如果有参数列表,new一个Object[],参数列表有多少个Object[]就有多长

Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        MethodParameter parameter = parameters[i];
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        args[i] = findProvidedArgument(parameter, providedArgs);

先声明args遍历parameters,给args[i]赋值,args[i]的值解析器解析了才有
* 解析之前,判断26个解析器是不是 supportsParamter支持这个参数类型。

this.resolvers.supportsParameter(parameter)
    - HandlerMethodArgumentResolverComposite.java的getArgumentResolver方法中
    - 获取一个缓存result
    - result==null,进入增强for循环,逐个确定26个解析器谁能支持这种参数
      + supportsParameter方法,传来的参数有没有hasParameterAnnotation标注注解
      + 没有就return false
      + 如果标了,再判断参数是否map类型,
      + return true支持解析
    - 当前resolver支持解析,放到缓存里边,判断成功,进入解析
  * **解析参数**
this.resolvers.resolveArgument
    - HandlerMethodArgumentResolverComposite.java的resolverArgument方法中,先拿到所有的参数解析器getArgumentResolver
    - 调用参数解析器的resolverArgument方法进行解析
      + 获取参数名字信息
      + 解析参数的名字,placeholderResolved、BeanExpressionResolver解析evaluate计算名字,按照正则匹配的方式
      + 解析参数的值
        * uriTemlateVars 在request请求域中拿到值;UrlPathHelper会把uri地址里边的所有的路径变量全部解析出来并保存到请求域中
  * 遍历循环所有参数
+ 最终返回args,args就是确定好的值
  • 处理返回结果的时候,把mavContainer传进去,
this.returnValueHandlers.handlerReturnValue
+ 在handlerMethod.java的getReturnValueType方法中获取返回的结果类型
+ HandlerMethodArgumentResolverComposite.java的handleReturnValue方法中, 找到返回值的处理器 如果返回值是一个字符串,拿到字符串然后保存到mavContainer
  • 返回值处理完以后,getModelAndView
  • 目标方法执行完成 将所有的数据都放在 ModelAndViewContainer;包含要去的页面地址View。还包含Model数据。
  • 从ModelAndViewContainer拿到默认的Model,updateBindingResult,拿到key放到绑定里边,又被封装成ModelAndView,然后返回这个新封装的mav
  • 处理派发结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

拿到所有请求域中的属性,解析得到视图名 渲染页面

view.render(mv.getModelInternal(),request,response);

拿到页面数据

createMergeOutputModel(model,request,response);
&#x521B;&#x9020;&#x5408;&#x5E76;&#x7684;&#x8F93;&#x51FA;&#x6A21;&#x578B;

如果model不等于空

mergeModel.putAll(model)//&#x5373;&#x628A;&#x6570;&#x636E;&#x8F6C;&#x79FB;&#x5230;HashMap

渲染合并输出的模型数据

renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
+ 把上面的Hashmap传进来了
+ 拿到请求对象,获取的原生的Servletrequest
return originalRequest
+ 暴露模型作为请求域属性
// Expose the model object as request attributes.
        exposeModelAsRequestAttributes(model, request);
  * 把model里面的东西进行遍历
  * 遍历以后每一个request setAttribute

Original: https://www.cnblogs.com/Salinger/p/16492350.html
Author: Lincee
Title: SpringMVC底层——请求参数处理流程描述

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/574004/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Java 内功修炼 之 数据结构与算法(二)

    一、二叉树补充、多叉树 1、二叉树(非递归实现遍历) (1)前提前面一篇介绍了 二叉树、顺序二叉树、线索二叉树、哈夫曼树等树结构。可参考:https://www.cnblogs.c…

    Linux 2023年6月11日
    069
  • 资源笔记

    Spring Cloud Stream中文指导文档 Original: https://www.cnblogs.com/iforeverhz/p/16274259.htmlAuth…

    Linux 2023年6月7日
    0101
  • Linus:“我删除了Linux,因为它就是个垃圾”

    1月 25日, Linus Torvalds 在 Linux 的 GitHub 仓库中提交了一个恶作剧 README页面,其备注名为《delete linux because it…

    Linux 2023年6月13日
    086
  • PHP安装和部署

    一、关闭防火墙 二、安装EPEL源、REMI源、yum源管理工具、PHP 7.3 ①安装epel源 [root@localhost yum.repos.d]# yum instal…

    Linux 2023年6月7日
    0113
  • 嵌入式软件架构设计-程序分层

    1 前言 在嵌入式MCU软件开发过程中,程序分层设计也是重中之重,关系到整个软件开发过程中的协同开发,降低系统软件的复杂度(复杂问题分解)和依赖关系、同时有利于标准化,便于管理各层…

    Linux 2023年6月7日
    0135
  • Xshell配置ssh免密码登录-密钥公钥(Public key)与私钥(Private Key)登录【已成功实例】

    本文转自https://blog.csdn.net/qjc_501165091/article/details/51278696 ssh登录提供两种认证方式:口令(密码)认证方式和…

    Linux 2023年5月28日
    080
  • centos挂载windows共享目录

    背景 在linux环境下访问远程windows的共享目录,将windows上的目录挂载到linux目录下。如下图: 一、windows上新建共享文件夹 windows设置共享目录 …

    Linux 2023年6月6日
    094
  • DEX文件解析–7、类及其类数据解析(完结篇)

    一、前言 前置技能链接:DEX文件解析—1、dex文件头解析DEX文件解析—2、Dex文件checksum(校验和)解析DEX文件解析–3、de…

    Linux 2023年6月8日
    080
  • zabbix监控配置项配置

    1.手动添加监控项 2. 使用模板添加监控项 3.0 邮件告警 创建主机并加入主机组 1.手动添加监控项 即获取数据的监控指标增加用户,修改用户,删除用户etc/passwd文件都…

    Linux 2023年6月7日
    0122
  • Shell 第二章《流控》

    前言 无论什么编程语言都离不开条件判断(流控)。SHELL也不例外。例如,用户输入的密码不够长时提示用户,你太短了例如,用户输入了备份的目录,如果有目录继续备份,如果没有目录创建目…

    Linux 2023年6月6日
    0132
  • Keytool配置 Tomcat的HTTPS双向认证

    keytool 简介 Keytool 是一个 Java数据证书的管理工具, Keytool将密钥(key)和证书(certificates)存在一个称为 keystore的文件中。…

    Linux 2023年6月6日
    0122
  • 【小记】腾讯云 Linux 虚拟机如何正确修改 hosts 文件

    如果直接修改 /etc/hosts 文件,重启后设置会丢失还原,原因是腾讯云虚拟机默认使用了 Cloud-Init 进行初始化操作。 参见:https://cloud.tencen…

    Linux 2023年6月13日
    083
  • 巧妙绕过 “您的链接不是私密链接”

    大家上网的时候,有时候会碰到Chrome提示”您的链接不是私密链接”, 运气好的话,点击高级,有一个选项是”继续浏览不安全的网页”,…

    Linux 2023年6月13日
    0112
  • ansible对文件内容操作

    bash;gutter:true; ansible lineinfile 简介 lineinfile该模块是操作文件中的每一行内容,他是按照行为单位的,和下面的replace模块并…

    Linux 2023年6月7日
    070
  • 可视化软件navicat

    目录 多表查询思路 可视化软件navicat *多表查询练习题 内容 多表查询思路 多表查询的思路总共就两种: 白嫖两个表 获取jason所在的部门名称 子查询 相当于是我们日常生…

    Linux 2023年6月7日
    069
  • 鞍点

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月7日
    0126
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球