关于springboot整合springmvc的源码分析可以参考以下系列文章:
- springboot整合springmvc源码分析(1)--前言
- springboot整合springmvc源码分析(2)--承上启下
- springboot整合springmvc源码分析(3)--直击内容
该源码分析系列文章分如下章节:
- springmvc源码分析(1)-- DispatcherServlet
- springmvc源码分析(2)-- HandlerMapping
- springmvc源码分析(3)-- HandlerAdapter
- springmvc源码分析(3.1)-- HandlerMethodReturnValueHandler
- springmvc源码分析(4)-- ViewResolver
HandlerAdapter默认有4种实现的适配器,其中包括对(Controller
/HttpRequestHandler
/Servlet
)的适配,起名是(SimpleControllerHandlerAdapter/HttpRequestHandlerAdapter/SimpleServletHandlerAdapter)不过这三个已经很少在使用,目前最常用的当属适配RequestMapping的适配器RequestMappingHandlerAdapter
HandlerAdapter接口有三个方法:
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
supports表示支持的所适配的Handler
handle执行逻辑方法返回ModelAndView
那本章自然是从这个比较常用的适配器RequestMappingHandlerAdapter讲起。
我们来看下他的supports方法:
这里就表明它仅支持适配HandlerMethod
我们还是像上一章那样springmvc源码分析(2)-- HandlerMapping,直接从springboot的WebMvcAutoConfiguration这里开始:
这里把RequestMappingHandlerAdapter交由spring管理,我们看看RequestMappingHandlerAdapter的类继承关系:
它实现了一个InitializingBean接口,所以我们直接着手afterPropertiesSet方法开始:
首先这里调用了initControllerAdviceCache方法:
ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
查找出所有增强类,就如springmvc实用篇 -- @ControllerAdvice该章使用到的,然后接着遍历
获取该增强类的@ModelAttribute并放入map
MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
以及获取@InitBinder并放入map
MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
接着判断该增强类是否实现了RequestBodyAdvice或者ResponseBodyAdvice后放入requestResponseBodyAdvice
接着回到:
下面就是进行一系列默认的HandlerMethodArgumentResolver创建和获取以及HandlerMethodReturnValueHandler,其中就包括我们springmvc实用篇 -- WebMvcConfigurer这一章中所自定义的配置
经过上面一系列动作整个RequestMappingHandlerAdapter就已经构建完了。
接着回到第一章springmvc源码分析(1)-- DispatcherServlet这里:
获取所有实现HandlerAdapter接口的bean ,然后放入DispatcherServlet.handlerAdapters的list里供选择适配器时使用
接着回到第一章springmvc源码分析(1)-- DispatcherServlet调用选择适配器:
循环遍历所有适配器,然后调用supports方法判断是否支持当前传入的handler,毫无疑问这里将返回RequestMappingHandlerAdapter这个适配器。
拿到处理器适配器之后就进入真正的controller调用和返回modelAndView
在调用之前将进行拦截器的applyPreHandle调用mappedHandler.applyPreHandle:
接着AbstractHandlerMethodAdapter.handle:
实际这里还是调用RequestMappingHandlerAdapter.handleInternal方法:
接着就是调用RequestMappingHandlerAdapter.invokeHandlerMethod,该方法下一系列操作包括加载argumentResolvers、returnValueHandlers、以及controllerAdvice方法的调用等等,这里就不对这些进行分析了,后续有时间再另开文章专门分析,我们关注它什么时候进行调用我们的controller,下面是该方法的部分代码:
接着执行:invokeAndHandle
然后接着:InvocableHandlerMethod.invokeForRequest
InvocableHandlerMethod.doInvoke :
到这里我们明显看到反射调用我们的controller的方法,将调用结果进行返回
InvocableHandlerMethod.invokeForRequest拿到返回值之后往下走就是调用HandlerMethodReturnValueHandlerComposite.handleReturnValue:
selectHandler选择一个合适的HandlerMethodReturnValueHandler
这里我们当是选择了RequestResponseBodyMethodProcessor(因为我们controller用的是@ResponseBody的话),具体参考springmvc源码分析(3.1)-- HandlerMethodReturnValueHandler;
当我们选择的是RequestResponseBodyMethodProcessor那么在执行handler.handleReturnValue的时候基本就已经完成了浏览器的响应。然后回到下面:
调用getModelAndView进行获取ModelAndView:
圈红位置我们注意到,如果选择的是RequestResponseBodyMethodProcessor那么这里将会是true,那么就将返回null,没有modelAndView,也就是不会再进入视图解析器,也就是完成了我们整个接口的调用和响应,如果选择的比如是ModelAndViewMethodReturnValueHandler,那么这里就会将会构造modelAndView然后进行返回,接着就是进入视图解析器的解析渲染了。
至此我们的适配器调用流程就已经很明朗了