上一篇有提到,当有、无这两个标签时,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. 两种实现方式mycat多租户,枚举分片,注解拦截

    第一种: 优点:支持进一步分片 缺点:schema配置繁琐 注解式  /*!mycat:schema=[schemaName] */   注意:这在navicat 里面是会报错的,请用命令行登陆myc ...

  2. Ubuntu 上查看硬件信息命令

    1.Mint 驱动程序管理器是由 Linux Mint 团队开发的一款系统工具软件,使得用户在Linux系统中可容易安装专有驱动,通过一个直观的界面.由于 Mint 驱动程序管理器具有独立性,它支持所 ...

  3. 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数

    Q 在MSDN的那个demo中,将设备名换成"A:"取A盘参数,先用资源管理器读一下盘,再运行这个程序可以成功,但换一张盘后就失败:换成"CDROM0"取CDR ...

  4. 项目部署到Tomcat报错

    1.今天晚上,我想把dojo项目部署到Tomcat中,结果发现部署不了,Tomcat报错.而且,这个错误白天时也碰到了. 错误具体详细如下: Publishing failed with multip ...

  5. JavaScript获取select下拉框中的第一个值

    JavaScript获取select下拉框中的第一个值 1.说明 获取select下拉框中的第一个值 2.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD ...

  6. PCI-E配置MSI中断流程解析

    在传统的pci中断体系中,每一个pci总线上的设备被分配一个特定的中断号,然后当设备需要中断cpu时,设备直接发出int信号,然后在cpu的inta引脚拉低的时候将自己的中断号放在数据总线上,一切都要 ...

  7. Java和Flex整合报错(一)

    1.错误描述 at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(Def ...

  8. IO网络模型

    多路处理模型MPM MPM是Apache2引入的一个概念,就是将结构模块化.把核心任务处理作为一个可插拔的模块,使其能针对不同的环境进行优化 在这个情况下,就诞生出了处理模式的概念 Prefork 实 ...

  9. css 超出规定行数自动隐藏

     单行overflow: hidden;text-overflow: ellipsis;white-space: nowrap;  多行(兼容各个浏览器)//通过覆盖最后几个字的形式p{positio ...

  10. JVM内存分析

    1.java内存模型分析 java虚拟机运行时数据存储区域包括线程隔离和线程共享两类,整个PC的内存图如下所示: 下面对以上内存区域说明: 1.1 register和cache 当代计算机一般有多个c ...