上一篇有提到,当有、无这两个标签时,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/> 源码解析的更多相关文章

  1. Mybatis 系列7-结合源码解析核心CRUD 配置及用法

    [Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...

  2. Mybatis 系列6-结合源码解析节点配置:objectFactory、databaseIdProvider、plugins、mappers

    [Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...

  3. spring mvc源码解析

    1.从DispatcherServlet开始 与很多使用广泛的MVC框架一样,SpringMVC使用的是FrontController模式,所有的设计都围绕DispatcherServlet 为中心来 ...

  4. Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析

    Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析 本文简要介绍了基于 Spring 的 web project 的启动流程,详细分析了 Spring 框架将开发人员基于 XML ...

  5. spring MVC cors跨域实现源码解析

    # spring MVC cors跨域实现源码解析 > 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就 ...

  6. spring MVC cors跨域实现源码解析 CorsConfiguration UrlBasedCorsConfigurationSource

    spring MVC cors跨域实现源码解析 spring MVC cors跨域实现源码解析 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议 ...

  7. Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析

    1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...

  8. springmvc源码解析MvcNamespaceHandler之<mvc:view-resolvers>

    说在前面 本次主要介绍springmvc配置解析. springmvc配置解析 本次介绍MvcNamespaceHandler. 进入到这个方法org.springframework.web.serv ...

  9. 源码解析.Net中IConfiguration配置的实现

    前言 关于IConfituration的使用,我觉得大部分人都已经比较熟悉了,如果不熟悉的可以看这里.因为本篇不准备讲IConfiguration都是怎么使用的,但是在源码部分的解读,网上资源相对少一 ...

  10. Spring5源码解析-Spring框架中的单例和原型bean

    Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...

随机推荐

  1. Scrum方法论

    产品负责人: 代表客户或未来游戏玩家.产品负责人需要确保所有有趣的功能都能在游戏中实现,还负责对游戏完整观感的理解. Scrum主管: 代表理性思维.需要主持每日Scrum会议,并确保每个人都在执行任 ...

  2. 我的Java设计模式-责任链模式

    今天来说说程序员小猿和产品就关于需求发生的故事.前不久,小猿收到了产品的需求. 产品经理:小猿,为了迎合大众屌丝用户的口味,我们要放一张图,要露点的. 小猿:......露点?你大爷的,让身为正义与纯 ...

  3. 远程控制你的智能电视,按键|输入|安装App等都已实现,已开源!

    一.序 Hi,大家好,我是承香墨影! 智能电视或者智能盒子,不知道大家了解多少? 这两年各大厂商生产的电视设备,基本上都是搭载的 Android 系统.既然电视本身就是 Android 系统的,我们也 ...

  4. linux远程控制

    linux远程控制 SSH协议:为客户机提供安全的shell环境,默认端口22OpenSSH服务服务名称:sshd主程序:/usr/sbin/sshd ,/usr/bin/ssh配置文件:/etc/s ...

  5. 使用阿里云主机离线部署CDH步骤详解

    一.Linux文件系统准备 1. 拍摄快照 登录阿里云控制台,拍摄快照,注意有几个关键点尽量拍摄快照,系统初始状态.CM环境准备完成.CM安装完成.CDH安装完成. 2. 挂载设备 三个主机都执行. ...

  6. 决策树之ID3、C4.5、C5.0等五大算法

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- C5.0决策树之ID3.C4.5.C5.0算法 ...

  7. Oracle SQL Developer中SQL语句格式化快捷键

    Oracle SQL Developer中SQL语句格式化快捷键 格式化SQL语句:Ctrl+F7

  8. Struts2实现文件上传(三)

    Struts2实现文件上传 配置文件web.xml <?xml version="1.0" encoding="UTF-8"?> <web-a ...

  9. C#之AES256位加密解密

    密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分 ...

  10. Linux显示用户注册名

    Linux显示用户注册名 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ finger -s Login Name Tty Idle Login Time Of ...