SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析
上一篇有提到,当有、无这两个标签时,SpringtMVC 底层所采用的 HandlerMapping 以及 HandlerAdapter 是不一样的。现在就来进行源码调试,揭开 SpringtMVC 底层实现的庐山真面目。
Demo代码地址:
https://github.com/cyhbyw/springMVC_atguigu_TongGang
工程名称:
springMVC_DebugSourceCode
现在开始调试。
====PS:图片可能不是很清晰,可以右击图片、选择在新标签页中查看(效果更好)===
先来看看没有这两个标签的情况下,SpringMVC的行为吧。提示:需要在XML配置文件中注释掉这两个标签的内容!
01. Bean定义文档的阅读器(其实就是读取XML配置文件中的内容);可以看到,SpringMVC 会读取到 component-scan 的元素,然后调用Line166的方法;注意线程堆栈信息,此方法位于 AbstractApplicationContext 的 Line501 的 refresh() 方法调用路径中(refresh() 方法是SpringIOC容器管理的核心方法,后面会再提及)

02. 解析元素;先调用 Line1339 的方法,再调用 Line1343 的方法;如图,Line1345 的 resolver() 方法很重要(后面详解)

03. 现在进入 resolve() 方法;然后调用 Line128 的 init() 方法

04. init() 方法就是注册一批Bean定义解析器;比如 Line35 就定义了 component-scan 元素的解析器

05. 注册的方式就是放入到 parsers 这个 map 中(这里放入,后面就会取出来使用)

06. 回到上一层,resolve() 方法处理完成后,调用 handler.parse() 方法

07. parse() 方法会先去找对应元素的 parser

08. 找的本质其实就是从刚才的 map 中取出对应元素的值

09. 找到 parser 后,继续调用 parse() 方法

10. 继续调用

11. 继续调用

12. 下面两张图片中断点所在行的 beanDefs.add(registerPostProcessor 方法的 registerPostProcessor() 方法会依次被调用(可以理解,或者说,等价于 for 循环调用,只是 SpringtMVC 还有其它的判断逻辑)


13. 继续调用 registerBeanDefinition() 方法

14. 通过 Line851 行将 beanName 添加到 beanDefinitionNames 中,以方便后续使用

15. 多次调用后,可以看到,beanDefinitionNames 中的元素数量在增加

16. XML 配置文件中定义的 component-scan 元素已经处理完成,现在继续处理 bean 元素(这是的 bean 元素其实是 XML 文件中定义的 InternalResourceViewResolver,只是没有为它的 id/name 赋值,所以下图中显示为 "bean: null")

17. 同理,InternalResourceViewResolver 会被添加到 beanDefinitionNames 中

18. 到目前为止,beanDefinitionNames 已经存入8个元素,是时候想想,什么时候会使用 beanDefinitionNames 了。
前面也提及过,AbstractApplicationContext 中有个 refresh() 方法,此方法是 SpringIOC 容器管理的核心方法,里面包含了对其它几个重要方法调用。
refresh() 方法非常重要!!!!
refresh() 方法非常重要!!!!
refresh() 方法非常重要!!!!
上面1--17步中方法的调用,其实都全部位于此处 Line501 的 obtainFreshBeanFactory() 方法中。现在,是时候转向其它方法的调用了。
调试发现,接下来 SpringtMVC 会走到 Line532 的 finishFresh() 方法。

19. 现在到达 DispatcherServlet 的 initStrategies() 方法;注意查看下图中的堆栈路径,有点多,不再详述了;同时,可以看到,此处 Line482 的 initHandlerMappings(context) & Line483 的 initHandlerAdapters(context) 方法其实就是从 context-->beanFactory-->beanDefinitionNames 中去获取 HandlerMapping & HandlerAdapter

20. 不好意思,获取不到(这个很容易理解,因为上面我们看到的 beanDefinitionNames 确定没有任何一个 HandlerMapping 或者 HandlerAdapter),于是代码转到 Line588 去获取默认值
21. 默认值是从 defaultStrategies 中获取

22. defaultStrategies 其实是采用 static{} 去读取 DispatcherServlet.properties 文件中的内容

23. 文件内容如下;默认两个 HandlerMapping 以及三个 HandlerAdapter (这就是没有配置这两个标签时 SpringtMVC 所采用的默认值)

24. 初始化 HandlerAdapter 的逻辑类似,不再详述

以上24步,是没有添加这两个标签时 SpringtMVC 的处理流程。接下来分析一下有这两个标签时的处理流程。
总体来说,大同小异,只是中间有个地方创建了不同的实例、然后调用了不用实例的方法、进而得到不同的Bean。
来具体看看吧。相同的逻辑不再赘述,下面的说明及配图主要体现在一些不同的点上。
01. 现在开始处理 annotation-driven 元素

02. 得到一个不同的 NamespaceHandler 并调用它的 init() 方法

03. 注册内容当然不一样;从图中可以明显看到,第一个就是 annotation-drivern 且对应的类是 AnnotationDrivenBeanDefinitionParser

04. 获取的时候,当然是拿到刚才注册进去的 AnnotationDrivenBeanDefinitionParser

05. parse() 方法自然也不一样;注意 Line204 行会注册 HANDLER_MAPPING_BEAN_NAME

06. 而这个 HANDLER_MAPPING_BEAN_NAME 其实就是 RequestMappingHandlerMapping

07. 可以看到 RequestMappingHandlerMapping 已经被成功地添加到 beanDefinitionNames 中(那么,后续使用时,就可以取出它)

08. 注册 HANDLER_ADAPTER_BEAN_NAME

09. HANDLER_ADAPTER_BEAN_NAME 其实就是 RequestMappingHandlerAdapter

10. 将 RequestMappingHandlerAdapter 添加到 beanDefinitionNames 中(之后就可以使用啦~~)

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析的更多相关文章
- Mybatis 系列7-结合源码解析核心CRUD 配置及用法
[Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...
- Mybatis 系列6-结合源码解析节点配置:objectFactory、databaseIdProvider、plugins、mappers
[Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...
- spring mvc源码解析
1.从DispatcherServlet开始 与很多使用广泛的MVC框架一样,SpringMVC使用的是FrontController模式,所有的设计都围绕DispatcherServlet 为中心来 ...
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析 本文简要介绍了基于 Spring 的 web project 的启动流程,详细分析了 Spring 框架将开发人员基于 XML ...
- spring MVC cors跨域实现源码解析
# spring MVC cors跨域实现源码解析 > 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就 ...
- spring MVC cors跨域实现源码解析 CorsConfiguration UrlBasedCorsConfigurationSource
spring MVC cors跨域实现源码解析 spring MVC cors跨域实现源码解析 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议 ...
- Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析
1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...
- springmvc源码解析MvcNamespaceHandler之<mvc:view-resolvers>
说在前面 本次主要介绍springmvc配置解析. springmvc配置解析 本次介绍MvcNamespaceHandler. 进入到这个方法org.springframework.web.serv ...
- 源码解析.Net中IConfiguration配置的实现
前言 关于IConfituration的使用,我觉得大部分人都已经比较熟悉了,如果不熟悉的可以看这里.因为本篇不准备讲IConfiguration都是怎么使用的,但是在源码部分的解读,网上资源相对少一 ...
- Spring5源码解析-Spring框架中的单例和原型bean
Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...
随机推荐
- Apache+PHP+Mysql中文配置
一.安装Apache2 1.输入sudo apt-get install apache2下载安装apache2 2.输入Y回车确认 3.安装成功 Apache安装完成后,默认的网站根目录是" ...
- ORACLE虚拟索引(Virtual Index)
ORACLE虚拟索引(Virtual Index) 虚拟索引概念 虚拟索引(Virtual Indexes)是一个定义在数据字典中的假索引(fake index),它没有相关的索引段.虚拟索引的目 ...
- Caffe︱构建lmdb数据集、binaryproto均值文件及各类难辨的文件路径名设置细解
Lmdb生成的过程简述 1.整理并约束尺寸,文件夹.图片放在不同的文件夹之下,注意图片的size需要规约到统一的格式,不然计算均值文件的时候会报错. 2.将内容生成列表放入txt文件中.两个txt文件 ...
- R语言︱贝叶斯网络语言实现及与朴素贝叶斯区别(笔记)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 一.贝叶斯网络与朴素贝叶斯的区别 朴素贝叶斯的 ...
- 集成电路883和883b有什么区别
根据用途,元器件的质量等级可分为:用于元器件生产控制.选择和采购的质量等级和用于电子设备可靠性预计的质量等级两类,两者有所区别,又相互联系. 用于元器件生产控制.选择和采购的质量等级 元器件的质量等级 ...
- FusionCharts 3D帕累托图
1.设计3D帕累托图的页面 Pareto3D.html: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN&q ...
- 检测dll是32/64位 ?
检测dll是32/64位 ? void CCheck32Or64Dlg::OnButton2() { CString fileName = ""; CFileDialog *fil ...
- word文档的动态添加数据
解释:其实主要的思路就是先把word文档转化成xml格式的数据,然后在把xml格式的数据转化成字节流让程序来读取,最后在把字节流转化成xml格式的数据,然后在转化成word文档. poi工具也是这个思 ...
- 当发现你的OpenStack虚拟机网络有问题,不妨先试一下这16个步骤
1. Security Group全部打开,这是最基本的,但是很多人容易忘记 其实遇到过无数这种场景了,Debug了半天网络问题,各种手段都用上了,最后发现安全组竟然没有打开. 2. 通过界面查看虚拟 ...
- CSS布局方案
居中布局 水平居中 1)使用inline-block+text-align 原理:先将子框由块级元素改变为行内块元素,再通过设置行内块元素居中以达到水平居中. 用法:对子框设置display:inli ...