在深入学习Spring mvc 过程中,我们需要了解如下两个类:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
RequestMappingHandlerMapping 是处理url method关系映射的,直白的说这个类里面维护着一个urlMap 存放着url路径与requestMappingInfo 的信息,通过这个映射就可以快速的找到执行的方法;
RequestMappingHandlerAdapter 是适配器,是用来执行RequestMappingHandlerMapping 映射的方法,里面定义了一些参数解析器等比如模型封装,@RequestParam 的解析等;
接下来就是具体分析这两个类:从以下三点进行展开:
1.这两个类在哪里被加载进来的 2.RequestMappingHanderMapping urlMap 如何装配的 3.RequestMappingHandlerAdapter 参数解析器如何装配;
1. 问题抛出:RequestMappingHanderMapping RequestMappingHandlerAdapter是什么时候加载到Sppring Bean 容器中的?
答:
得益于我们在x m l中配置的 <mvc:annotation-driven/> 标签
在spring 强大的扩展机制下,Spring webmvc包 org.springframework.web.servlet.config.MvcNamespaceHandler类
org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser 类有对该标签的定义与解析如下:
我们看解析parse方法 做了什么事情:
在spring 容器中注册RequestMappingHandlerMapping
在Spring容器中注册RequestMappingHandlerAdapter
好了,其实还注册了其他的类,这里我们就截图这两个;
到这里就很明朗了,这两个类被注册到了Spring be an 工厂了,那么在Spring 最后会进行全部的实例化;
2.问题抛出:RequestMappingHanderMapping urlMap 如何装配的;
答:
在第一个问题中,我们知道了,RequestMappingHanderMapping 被装载进入了Spring bean 容器中,最终会被实例化;那么我们看一看,它实例化做了什么事情;
自下而上看一下它的类结构图:
可知,它实现了InitializingBean接口,其方法 afterPropertiesSet() 会在初始化的时候被调用;看一下
会触发initHandlerMethods() 方法,去寻找处理的方法:我们继续往下点:
这个方法就是会到spring 容器中找到所有的be an 然后在be an 中找到需要的handler 方法;主要是isHandler(...)这个方法的判段:
它会 判断我们的bean 是否有Controller 注解或者RequestMapping 注解,带有这种注解的be an 才会被留下来,进行下一步的操作;
找到匹配的Handler 之后,就进行检测Handler 方法: detectHandlerMethods(beanName);
扫描到所有匹配的方法,具体的方法,参数,注解信息,全部放入 RequestMappingInfo中;
执行 getMappingForMethod 获取到RequestMapping 信息以及方法信息并生成RequestMappingInfo 对象进行封装
然后注册HandlerMethod:
参数-requestInfoMapping 映射放入urlMap 中
这样在初始化的过程中所有的url 映射都已经装配进入内存中了;
3. 问题抛出: RequestMappingHandlerAdapter 参数解析器如何装配:
答:
我们看一下org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter 类它也实现了 InitializingBean接口
getDefaultArgumentResolvers()得到默认的参数解析器:
@RequestBody @ModelAttribute
@RequestParam @CookieValue @RequestHeader
原始数据解析,模型pojo解析 都会被加载进内存
getDefaultInitBinderArgumentResolvers()默认的绑定参数解析:
像@Value @PathVariable等常用的注解解析器就会被加载进来;
以上这两种都属于参数解析器,会加入到 argumentResolvers链表中
getDefaultReturnValueHandlers();默认的返回参数解析器 比如@ResponseBody
最终会被加载 returnValueHandlers 链表中
这样参数解析器就装配好了