SpringtMVC中配置 源码解析

时间:2023-03-09 15:48:57
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容器管理的核心方法,后面会再提及)

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

10. 继续调用

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

11. 继续调用

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

13. 继续调用 registerBeanDefinition() 方法

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

18. 到目前为止,beanDefinitionNames 已经存入8个元素,是时候想想,什么时候会使用 beanDefinitionNames 了。

前面也提及过,AbstractApplicationContext 中有个 refresh() 方法,此方法是 SpringIOC 容器管理的核心方法,里面包含了对其它几个重要方法调用。

refresh() 方法非常重要!!!!

refresh() 方法非常重要!!!!

refresh() 方法非常重要!!!!

上面1--17步中方法的调用,其实都全部位于此处 Line501 的 obtainFreshBeanFactory() 方法中。现在,是时候转向其它方法的调用了。

调试发现,接下来 SpringtMVC 会走到 Line532 的 finishFresh() 方法。

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

20. 不好意思,获取不到(这个很容易理解,因为上面我们看到的 beanDefinitionNames 确定没有任何一个 HandlerMapping 或者 HandlerAdapter),于是代码转到 Line588 去获取默认值SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

21. 默认值是从 defaultStrategies 中获取

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

以上24步,是没有添加这两个标签时 SpringtMVC 的处理流程。接下来分析一下有这两个标签时的处理流程。

总体来说,大同小异,只是中间有个地方创建了不同的实例、然后调用了不用实例的方法、进而得到不同的Bean。

来具体看看吧。相同的逻辑不再赘述,下面的说明及配图主要体现在一些不同的点上。

01.  现在开始处理 annotation-driven 元素

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

06. 而这个 HANDLER_MAPPING_BEAN_NAME 其实就是 RequestMappingHandlerMapping

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

08. 注册 HANDLER_ADAPTER_BEAN_NAME

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

09. HANDLER_ADAPTER_BEAN_NAME 其实就是 RequestMappingHandlerAdapter

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析

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

SpringtMVC中配置 <mvc:annotation-driven/> 与 <mvc:default-servlet-handler/> 源码解析