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通过& ...
随机推荐
- eclipse调试hadoop2.2.0源码笔记
在hadoop1.x版本时使用的是在Windows下编译Eclipse插件,远程调试集群.换成2.2.0,没有eclipse-plugin文件. hadoop2.2.0"远程调试集群&quo ...
- js数据类型的判断方法
判断js中的数据类型有一下几种方法:typeof.instanceof. constructor. prototype. $.type()/jquery.type(),接下来主要比较一下这几种方法的异 ...
- Linux内核开发之将驱动程序添加到内核
驱动程序添加到内核 一.概述: 在Linux内核中增加程序需要完成以下三项工作: 1.将编写的源代码复制到Linux内核源代码的相应目录 2.在目录的Kconfig文件中增加新源代码对应项目的编译配置 ...
- pycaffe︱caffe中fine-tuning模型三重天(函数详解、框架简述)
本文主要参考caffe官方文档[<Fine-tuning a Pretrained Network for Style Recognition>](http://nbviewer.jupy ...
- 学习笔记︱深度学习以及R中并行算法的应用(GPU)
笔记源于一次微课堂,由数据人网主办,英伟达高级工程师ParallerR原创.大牛的博客链接:http://www.parallelr.com/training/ 由于本人白痴,不能全部听懂,所以只能把 ...
- R语言︱情感分析—词典型代码实践(最基础)(一)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 笔者寄语:词典型情感分析对词典要求极高,词典中 ...
- struts2的配置文件
struts2的配置文件 1.配置Action的struts.xml 2.配置Struts2有关属性的struts.properties
- W: 无法下载 bzip2:/var/lib/apt/lists/partial/extras.ubuntu.com_ubuntu_dists_trusty_main_source_Sources
1 错误描述 youhaidong@youhaidong:~$ cd 下载 youhaidong@youhaidong:~/下载$ sudo apt-get update 忽略 http://cn.a ...
- Struts2(七) Struts2访问Servlet的API
当接受表单参数,向页面保持数据时.要用到Struts访问Servlet 的API .下面只做参考,有错误或不同意见可以发送邮箱2440867831@qq.com .建议大家看struts文档,源代码 ...
- val(),text(),html()的区别
<script type="text/javascript" src="js/jquery-1.8.3.min.js"></script> ...