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 ...
随机推荐
- String、StringBuffer、与StringBuilder的区别
转载自博客园,原文链接:String.StringBuffer.与StringBuilder的区别 相信大家都知道StringBuffer.StringBuilder,但是这两个的用法都差不多,到底有 ...
- UVA-804 模拟
将每个translation的输入和输出place全部记录下来,模拟即可,当所有translation都不能工作时,就说明dead了. AC代码: #include<cstdio> #in ...
- mongodb Decimal Spring data mongodb Decimal128 SpringMvc 序列化字符串 json converter
Mongodb 3.4 就开始支持Decimal 类型,解决double的精度问题,但是不太好用,MapReduce的时候Array.sum 也不能计算 Decimal.比较坑,但是聚合可以用 Spr ...
- 吾八哥学Selenium(四):操作下拉框select标签的方法
我们在做web页面自动化测试的时候会经常遇到<select></select>标签的下拉框,那么在Python里如何实现去操作这种控件呢?今天就给大家分享一下这个玩法.为了让大 ...
- 分享一个Appium/selenium测试报告模板
介绍 这个模板改编自 这位外国老哥 效果图 错误截图 录像 失败的case可以点击"view"查看报错信息, 也可以点击screenshot查看截图信息,更可以点击replay查看 ...
- C++ 监测磁盘空间
硬盘管理器 头文件 HardDiskManager.h : #if _MSC_VER > 1000 #pragma once #endif #include <windows.h> ...
- R语言︱贝叶斯网络语言实现及与朴素贝叶斯区别(笔记)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 一.贝叶斯网络与朴素贝叶斯的区别 朴素贝叶斯的 ...
- java Socket实现简单在线聊天(一)
最近的项目有一个在线网页交流的需求,由于很久以前做过的demo已经忘记的差不多了,因此便重新学习一下. 我计划的大致实现步骤分这样几大步: 1.使用awt组件和socket实现简单的单客户端向服务端持 ...
- grub2与grub区别
关于版本: GRUB2 使之版本号为1.98之后的grub:GRUB legacy(版本为0.97)是指GRUB,而非GRUB2,grub是指 grub1.97 和以前的,grub 2 指的是 gru ...
- APACHE服务器出现No input file specified.的完美解决方案
启用REWRITE的伪静态功能的时候,首页可以访问,而访问内页的时候,就提示:“No input file specified.” 原因在于使用的PHP是fast_cgi模式,而在某些情况下,不能正确 ...