先来看一下一个rest请求到来之后,请求的处理流程图:
看过我之前博文的同学,应该了解了一个请求的大致处理流程,但是之前说的比较简略,这里我稍微详细一些:
1.Rest请求到来之后,被DispatchServlet拿到,进入到doDispatch方法中
2.遍历所有的handlermapping,一直到某个handlerMapping找到了请求路径对应的HandlerExecutionChain,HandlerExecutionChain其中核心就是某个Controller对应的方法
3.根据第2步中找到的HandlerExecutionChain,遍历所有的HandlerAdapter,直到找到能够支持HandlerExecutionChain中的handler的HandlerAdapter为止。其实这里判断的很水,就是看handler是不是HandlerMethod的对象。用的最多的就是RequestMappingHandlerAdapter,下面以RequestMappingHandlerAdapter为例来看看执行流程。
4.调用RequestMappingHandlerAdapter的handleInternal方法,这个方法会返回ModelAndView。具体调用流程如下:
4.1handleInternal调用invokeHandlerMethod(request, response, handlerMethod),invokeHandlerMethod也是RequestMappingHandlerAdapter中的方法,参数handlerMethod就是我们在第2步中找到的handler。这个handler会被封装成ServletInvocableHandlerMethod,然后进行调用,具体调用步骤如下:
4.1.1获取具体的请求参数:Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
4.1.1.1解析参数的时候用到了一个非常牛逼的东西:HandlerMethodArgumentResolverComposite,这是一个组合模式,里面包含了26个HandlerMethodArgumentResolver,那么究竟会选择哪一个resolver呢?其实在装载前SpringMVC就已经排好顺序了,当然也不是说排在最前面就一定要执行,这个还是要看resolver对参数是否真正的支持。一般来说我们的rest请求参数是JSON格式,那么请求参数里面往往会有一个@RequestBody这样的注解,RequestResponseBodyMethodProcessor这个HandlerMethodArgumentResolver优先级很高,而且他专门支持对@RequestBody注解的参数解析,所以在rest请求中,它的使用频率非常的高。找到这个HandlerMethodArgumentResolver之后,会调用它的resolveArgument方法来解析参数,其中解析是使用了它内部的StringHttpMessageConverter这个messageConverter来进行数据的真正解析,为什么选择这个Converter,是考虑到了请求中的Content-type等一系列要素,就这样请求参数被解析好了。
4.1.2利用4.1.1中得到的请求参数,进行反射调用,获得返回结果值。这个值就是returnValue
4.1.3拿到returnValue直接返回不就好了吗?怎么可能捏~~有时候我们的方法返回的是String,有时候返回的是User这样的对象,浏览器怎么去解析呢?所以我们还要对returnValue进行解析,怎么解析?ServletInvocableHandlerMethod中的成员returnValueHandlers会对这个返回值做解析,这个returnValueHandlers是HandlerMethodReturnValueHandlerComposite类型的,没错又是一个组合模式。解析步骤如下:
4.1.3.1选择一个HandlerMethodReturnValueHandler,哇又是一个handler,而且说到选择,肯定SpringBoot又装载了一堆handler进去,对的,HandlerMethodReturnValueHandlerComposite类似于前面参数解析的HandlerMethodArgumentResolver,又要根据HandlerMethodReturnValueHandler的优先级和对返回参数的支持来进行选择。这里,我们的RestController非常巧,选择的HandlerMethodReturnValueHandler又是RequestResponseBodyMethodProcessor,这个玩意儿支持@ResponseBody注解的method,所以它又被选中了!
4.1.3.2调用writeWithMessageConverters处理返回值。这个方法逻辑非常的复杂,我只讲讲关键思路:
4.1.3.2.1List
4.1.3.2选择一个支持这种mediaType的messageConverter,RestController选择了MappingJackson2HttpMessageConverter来返回给客户端,至此全部结束。
这里为什么我要大篇幅的讲处理流程,是因为后面我会自定义一些resovler进去和一些messageConverter进去,帮助大家更好的去理解,我们写了那么多的MVC程序,但是对于其中的消息转换,以及其中方法处理的适配,还是值得我们去研究的。