SpringtMVC运行流程:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的(源码理解)
在平时开发SpringtMVC程序时,在Controller的方法上,通常会传入如Map、HttpServletRequest类型的参数,并且可以方便地向里面添加数据。同时,在Jsp中还可以直接使用request等对象方便地获取出来。
如下面2图所示:
可问题是:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的?
带着这个问题,写了个简单的Demo,来进行源码调试。
Demo代码地址:
https://github.com/cyhbyw/springMVC_atguigu_TongGang
工程名称:
springMVC_DebugSourceCode
===============================以下是源码调试=========================================
01.首先,浏览器发出的请求到DispatcherServlet;然后,找到合适的HandlerAdapter(此处是RequestMappingHandlerAdapter);然后调用RequestMappingHandlerAdapter的handle()方法。此时,方法堆栈从Line959开始。
02.还是在DispatcherServlet的Line959的doDispatch()方法内,又调用了几个方法,到达invokeForRequest()方法;顾名思义,此方法会真正的调用Request方法(即Controller中的方法);不过,先会在Line128解析参数。
03.解析参数的方法又会走到Line161.
04.再经过两个方法的调用,可以看到上述的参数解析方法是直接返回了 mavContainer.getModle()
05.而getModel() 方法返回 defaulutModel 的成员变量。
06. defaulutModel 其实就是一个 BindingAwareModelMap
07.回到刚才的Line161,可以看到 args[i] 指向了刚才得到的BindingAwareModelMap,且内存地址是5010。
08.再返回一层,此处的 Object[] args 还是BindingAwareModelMap@5010,且其中的元素为空;此处Line136的 doInvoke(args) 方法就是通过反射调用真实的Controller中的方法。
09.真实Controller方法调用返回后,可以看到 mavContainer 对象中的 defaultModel 属性已经被赋值,且这个值就是BindingAwareModelMap@5010,与args是同一个对象(非常重要)!!!!
(备注:SpringMVC是如何为mavContainer 对象中的 defaultModel 属性赋值的,最开始调试了很久也没有发现,心想着,它既然是个Map,那应该是调用setXXX(), put(), putAll()这样的方法赋值进去的,但调试了很久始终没发现这样的方法被调用;同时,也可以确定它是在Line136行调用后就被赋值的;最后猜测,是同一个对象引用;现在,证明确实如此)
再啰嗦一句,其实就是:Line128的 Object[] args 变量指向了 mavContainer 对象的 defaultModel 属性!所以在将 args 通过Line136反射调用真实的Controller方法并填充数据后,defaultModel中也就有了相应数据!
10.控制台打印的入参Map其实也是BindingAwareModelMap(遗憾的是没有拿到内存地址;但还是可以辅助证明09中的结论)
11.真实Controller方法调用完成后,开始处理返回值
12.设置视图名称
13.准备创建ModelAndView对象
14.从 mavContainer 中取出Model数据,并通过构造函数传入ModelAndView
15.已经获得ModelAndView对象,进行后续操作(如渲染);注意,此时DispatcherServlet中的方法堆栈从Line971开始。
16.准备渲染
17.得到View对象
18.遍历 viewResolvers 找到一个合适的就返回给17步中的View对象
19.准备渲染
20.将Model数据暴露为RequestAttribute
21.暴露的本质其实是:request.setAttribute(modelName, modelValue)
22.最后是一个转发操作
SpringtMVC运行流程:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的(源码理解)的更多相关文章
- .NET Core 3.0之深入源码理解Startup的注册及运行
原文:.NET Core 3.0之深入源码理解Startup的注册及运行 写在前面 开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程 ...
- 【春华秋实】深入源码理解.NET Core中Startup的注册及运行
写在前面 开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程序的起点.通过使用Startup,可以配置化处理所有向应用程序所做的请求的 ...
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除 ...
- 在.NET Core中三种实现“可插拔”AOP编程方式(附源码)
一看标题肯定会联想到使用动态编织的方式实现AOP编程,不过这不是作者本文讨论的重点. 本文讨论另外三种在netcore中可实现的方式,Filter(过滤器,严格意义上它算是AOP方式),Dynamic ...
- MVC中使用SignalR打造酷炫实用的即时通讯功能附源码
前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯.由于当时走的太急,忘记把代码拿出来.想想这已经是大半年前的事情了,时间过 ...
- Asp.net Core中SignalR Core预览版的一些新特性前瞻,附源码(消息订阅与发送二进制数据)
目录 SignalR系列目录(注意,是ASP.NET的目录.不是Core的) 前言 一晃一个月又过去了,上个月有个比较大的项目要验收上线.所以忙的脚不沾地.现在终于可以忙里偷闲,写一篇关于Signal ...
- 从Mybatis源码理解jdk动态代理默认调用invoke方法
一.背景最近在工作之余,把开mybatis的源码看了下,决定自己手写个简单版的.实现核心的功能即可.写完之后,执行了一下,正巧在mybatis对Mapper接口的动态代理这个核心代码这边发现一个问题. ...
- 2018.11.20 Struts2中对结果处理方式分析&struts2内置的方式底层源码剖析
介绍一下struts2内置帮我们封装好的处理结果方式也就是底层源码分析 这是我们的jar包里面找的位置目录 打开往下拉看到result-type节点 name那一列就是我们的type类型取值 上一篇博 ...
- Winforn中DevExpress的TreeList中显示某路径下的所有目录和文件(附源码下载)
场景 Winform中DevExpress的TreeList的入门使用教程(附源码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...
随机推荐
- POJ - 1860 Bellman-Ford判正环
心累,陕西邀请赛学校不支持,可能要自费了.. 思路:套用Bellman-Ford判断负环的思路,把大于改成小于即可判定是否存在从源点能到达的正环.如果存在正环,那么完全多跑几次正环就可以把钱增加到足够 ...
- CodeForces - 796D Police Stations bfs
思路:删除尽量多的边使得所有点都能在限制距离之内到达一个警局,删除边会形成多棵子树,最多只能k棵.其实就是以每个警局为根结点,把整棵树划分为以警局为根结点的k棵树,说明要删除的边的数量就是k-1条,即 ...
- AES对称加密
import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.Secre ...
- MySQL InnoDB表压缩
MySQL InnoDB表压缩 文件大小减小(可达50%以上) ==> 查询速度变快(count * 约减少20%以上时间) 如何设置mysql innodb 表的压缩: 第一,mysql的版本 ...
- requests+多进程poll+pymongo实现抓取小说
今天看着有个很吸引人的小说作品信息:一家只在深夜开门营业的书屋,欢迎您的光临.作为东野奎吾<深夜食堂>漫画的fans,看到这个标题按捺不住我的好奇心........ 所以我又抓下来了,总共 ...
- JAVA多线程与并发学习总结
1. 计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...
- CDN中前端层的复制
前端层的复制是为了提高静态内容分发的性能和可扩展性.将静态内容的分发转由边缘服务器来完成是为了解决可扩展性的问题,因为这样做可以避免出现在对等点和广域网链路处的网络拥堵风险,而这两个地方的拥堵是网络延 ...
- 解决ios不支持按钮:active伪类的方法
mozilla开发社区上有 :active 不起作用的答案: [1] By default, Safari Mobile does not use the :active state unless t ...
- qwe框架- CNN 实现
CNN实现 概述 我在qwe中有两种,第一种是按照Ng课程中的写法,多层循环嵌套得到每次的"小方格",然后WX+b,这样的做法是最简单,直观.但是效率极其慢.基本跑个10张以内图片 ...
- PHP openssl函数库
php openssl 函数库中.提供了大量的函数.但是我们一般用的最多的,就是 openssl_encrypt string openssl_encrypt ( string $data , str ...