接前面的“SpringMVC启动分析”
继续……
作为一个Servlet,请求时从doGet和doPost开始的
DispatcherServlet的doGet和doPost是从FrameworkServlet继承来的
d5d02a4bc23561b1709ffff92415f99b.pngproce***equest()中主要是调用doService()方法,它是在DispatcherServlet中具体实现的
df8b3de84ba123c0bc41e12571fad849.pngdoService中主要是调用doDispatch方法
22e87451b49eb9b4cf1af490c0fdd350.png 51e6a29fd4f6b71a32eb691735e1bd84.png这个方法就是SpringMVC处理过程的宏观流程,从这里可以看出大致流程如下:
(1)判断是否有文件上传,如果有,请求转成MultipartHttpServletRequest
(2)从HandlerMapping中查找请求对应的Handler,并返回一个HandlerExecutionChain。这个处理器执行链中包含了处理器和拦截器。
(3)查找Handler对应的HandlerAdapter
(4)依次调用拦截器的preHandle方法
(5)通过HandlerAdapter的handle方法去调用处理器的目标方法,并返回ModelAndView对象
(6)依次调用拦截器的postHandle方法
(7)渲染视图(找到具体的视图页面,并填充模型数据),并依次调用拦截器的afterCompletion方法
上面这个过程有几个疑问:
疑问1:怎么找到HandlerMapping的?
疑问2:怎么找到HandlerAdapter?为什么要Adapter?
下面具体来看一下
怎么找HandlerMapping?
6ed46e08630e438c792bada38162c97e.png这是默认的HandlerMapping和HandlerAdapter组件,这里我们只看其中一种,基于注解的实现
与之对应的是DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter
先看DefaultAnnotationHandlerMapping
a0bc7c769cc22d04df65d19bcf46ad27.pngDefaultAnnotationHandlerMapping间接实现了ApplicationContextAware接口,所以在WebApplicationContext创建完成以后会回调setApplicationContext()方法,而在这个方法中又调用了initApplicationContext()方法,它是在子类中实现的,所以,对应DefaultAnnotationHandlerMapping而言,它最终调用的是AbstractDetectingUrlHandlerMapping中的initApplicationContext()方法。下面看一下它长什么样?
877a00ba362f9fe400b2a16adc81b387.png b9bc2ae5ac89a914eaf11da5d07c5b53.png上面两步所做的工作就是找到全部的映射URL,查找的依据如下:
(1)看Bean上面有没有@RequestMapping注解,如果有,遍历Bean中所有的方法,在方法是同样是找@RequestMapping注解,如果找到了,则两个@RequestMapping注解的value值拼接在一起就是一个url
(2)如果Bean上面没有@RequestMapping注解,直接在其方法上找,同样返回注解value值
举个例子:
1ca79ad36df0a185a7a2ee6155f20522.png这个Controller会产生3个url映射
9143b43c2e6980c61485573fa9fe0732.png这样就可以找到所有的映射Url,并以数组形式返回。也就是说,每次返回的String[]中的url对应的处理器是同一个。
到此为止,我们就知道了,是怎么根据请求uri找到对应的Controller的,原来是因为SpringMVC启动的时候就已经建立好了这种映射关系。
这里顺带提一句,默认的HandlerMapping并不只是DefaultAnnotationHandlerMapping这一个,还有一个是BeanNameUrlHandlerMapping,它是根据Bean的名字来识别的,以"/"开头的就是。
f92e93b0db7fa11554159814cb9c3e54.png接下来看第2个问题
HandlerAdapter是干什么的?为什么需要Adapter?
首先,为什么需要Adapter,明明已经拿到Handler对象了干嘛不直接调用具体的方法呢,还要通过Adapter去调用具体的方法?
我觉得,有这样几个原原因
1、屏蔽底层实现的差异和复杂度。创建Controller的方式有很多种,基于注解来创建只是其中一种,不同类型的处理器,有不同类型的Adapter,但最终还是HandlerAdapter。(PS:感觉有点像策略模式呀)
2、适配不同类型的处理器。这跟第一点很类似,Adapter适配器,就想一个插排一样,可以适配各种插头,HandlerAdapter就是插排,其实现类就是插头。
41f7d6fa45783037284b5ed21d26b846.png接下来,具体看一下AnnotationMethodHandlerAdapter是如何处理的
5fff7c56c65ab44240ac0e7c08fb3cb8.png找Handler中有@RequestMapping注解的方法,通过url匹配到具体的Method,这个Method已经是反射后的Method对象,然后调用。具体步骤其实很复杂,这里不细看了。
网友评论