接前面的“SpringMVC启动分析”

继续……

作为一个Servlet,请求时从doGet和doPost开始的

DispatcherServlet的doGet和doPost是从FrameworkServlet继承来的

SpringMVC请求处理过程_第1张图片

proce***equest()中主要是调用doService()方法,它是在DispatcherServlet中具体实现的

SpringMVC请求处理过程_第2张图片

doService中主要是调用doDispatch方法

SpringMVC请求处理过程_第3张图片

SpringMVC请求处理过程_第4张图片


这个方法就是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

SpringMVC请求处理过程_第5张图片

DefaultAnnotationHandlerMapping间接实现了ApplicationContextAware接口,所以在WebApplicationContext创建完成以后会回调setApplicationContext()方法,而在这个方法中又调用了initApplicationContext()方法,它是在子类中实现的,所以,对应DefaultAnnotationHandlerMapping而言,它最终调用的是AbstractDetectingUrlHandlerMapping中的initApplicationContext()方法。下面看一下它长什么样?

SpringMVC请求处理过程_第6张图片

SpringMVC请求处理过程_第7张图片

上面两步所做的工作就是找到全部的映射URL,查找的依据如下:

(1)看Bean上面有没有@RequestMapping注解,如果有,遍历Bean中所有的方法,在方法是同样是找@RequestMapping注解,如果找到了,则两个@RequestMapping注解的value值拼接在一起就是一个url

(2)如果Bean上面没有@RequestMapping注解,直接在其方法上找,同样返回注解value值


举个例子:

SpringMVC请求处理过程_第8张图片

这个Controller会产生3个url映射

9143b43c2e6980c61485573fa9fe0732.png


这样就可以找到所有的映射Url,并以数组形式返回。也就是说,每次返回的String[]中的url对应的处理器是同一个。

到此为止,我们就知道了,是怎么根据请求uri找到对应的Controller的,原来是因为SpringMVC启动的时候就已经建立好了这种映射关系。


这里顺带提一句,默认的HandlerMapping并不只是DefaultAnnotationHandlerMapping这一个,还有一个是BeanNameUrlHandlerMapping,它是根据Bean的名字来识别的,以"/"开头的就是。

SpringMVC请求处理过程_第9张图片


接下来看第2个问题

HandlerAdapter是干什么的?为什么需要Adapter?

首先,为什么需要Adapter,明明已经拿到Handler对象了干嘛不直接调用具体的方法呢,还要通过Adapter去调用具体的方法?

我觉得,有这样几个原原因

1、屏蔽底层实现的差异和复杂度。创建Controller的方式有很多种,基于注解来创建只是其中一种,不同类型的处理器,有不同类型的Adapter,但最终还是HandlerAdapter。(PS:感觉有点像策略模式呀)

2、适配不同类型的处理器。这跟第一点很类似,Adapter适配器,就想一个插排一样,可以适配各种插头,HandlerAdapter就是插排,其实现类就是插头。

SpringMVC请求处理过程_第10张图片

接下来,具体看一下AnnotationMethodHandlerAdapter是如何处理的

SpringMVC请求处理过程_第11张图片

找Handler中有@RequestMapping注解的方法,通过url匹配到具体的Method,这个Method已经是反射后的Method对象,然后调用。具体步骤其实很复杂,这里不细看了。


到此为止,请求处理部分就算是完结了~~~