Spring MVC原理学习笔记

114 阅读5分钟

前言

自己学习总结和整理的,内容可能有错误,还望多多指教

springmvc执行流程图

image.png

image.png

springboot加载spring mvc配置

image.png

image.png

image.png

image.png

image.png

servlet3.0的规范,spring通过实现ServletContainerInitializer接口,重写了onStartup,这里spring重写了onStartUp方法,传入所有实现了WebApplicationInitializer接口,实现了类似web.xml这样的初始化配置

参考地址:docs.spring.io/spring-fram…

spring mvc 初始化

image.png

image.png

image.png

spring mvc初始化主要是HttpServietBean、FrameworkServlet和DispatcherServlet, HttpServietBean负责加载Servlet配置,FrameworkServlet负责WebApplicationContext初始化,DispatcherServlet负责初始化HandlerMapping、HanlerAadapter等组件。在springboot-web,整个初始化过程是懒加载,当应用的第一个请求进来时在开始初始化。

参考链接:SpringMVC 初始化流程分析 - 掘金 (juejin.cn)

执行过程

DispatcherServlet

请求进来之后,先执行FrameworkServlet.processRequest方法,

image.png

在这个方法中,有几点关注

  1. localeContext 是本地化一些配置,LocaleContextHolder维护了一个ThreadLocal来保存这个,我们在当前线程的任何方法里可以直接调用LocaleContextHolder获得localeContext。
  2. RequestContextHolder和1的用户一样,里面两个ThreadLocal,保存了RequestAttributes。
  3. 释放LocaleContextHolder和RequestContextHolder
  4. 发布一个请求结束的事件,我们可以监听这个事件

image.png

调用doService方法,主要是配置一些属性等等,主要看doDispatch方法

image.png

调用getHandler获得HandlerExceutionChain(处理器执行链)。

image.png

HandlerMapping的作用就是根据request找到相应的处理器Handler和Interceptors(拦截器),上图可以看到HandlerMapping有很多实现类,主要关注一下日常开发常用的@Controller @RequestMapping方式。

AbstractHandlerMapping

image.png

所有的HandlerMapping都是继承自AbstractHandlerMapping,首先看一下这个类型的初始化方法

image.png

主要是用来初始化拦截器(实现HandlerInterceptor接口)的。

image.png

  1. 获取handler,这个是由子类来实现的
  2. 添加拦截器
  3. 处理跨域

AbstractHandlerMethodMapping

这个类的体系下有三个类,AbstractHandlerMethodMapping、RequestMappingInfoHandlerMapping、RequestMappingHandlerMapping。其他的Handler一个类代表一个handler,而@RequestMapping这种一个方法代表一个handler。

image.png

初始化,AbstractHandlerMethodMapping实现了InitializingBean接口(是spring bean初始化三种实现方式),主要是找到使用了@controller, @requestmapping这几个注解的bean,然后找到bean中的method,根据请求路径,放入一个HashMap的缓存中。

image.png

获取Handler,根据request的请求路径,取mappingRegistry中匹配一个适合的HandlerMethod,返回返回。

详细过程参考:SpringMVC 九大组件之 HandlerMapping 深入分析 - 掘金 (juejin.cn)

HandlerAdapter

image.png

image.png

SpringMVC拿到具体HandlerAdapter来具体执行方法,这里用到适配器模式,不同的Handler的具体执行方式也不同,这里就需要HandlerAdapter。

image.png

在执行HandlerAdapter之前,需要执行拦截器的preHandle方法。

HandlerAdapter有很多类型,但是这里主要关注的是RequestMappingHandlerAdapter,它的父类AbstractHandlerMethodAdapter实现了HandlerAdapter接口,但是具体集体方法都交给了子类去实现。

RequestMappingHandlerAdapter

初始化

image.png

RequestMappingHandlerAdapter 实现了InitializingBean接口,在初始化中做的事情是:

  1. 查找所有标记了@ControllerAdvice注解的Bean,保存起来;在这里类中找到方法标注了@ModelAttribute, 缓存起来;在这些类中找到方法标注了@InitBinder,缓存起来; 查找实现了RequestBodyAdvice或者ResponseBodyAdvice的类,然后缓存起来。

2、3、4主要是对argumentResolvers(参数解析器)、initBinderArgumentResolversreturnValueHandlers(返回处理器)进行初始化。

上面这些都可以进行自定义扩展,详细的可以看参考资料。这里需要注意一个RequestResponseBodyMethodProcessor类,这个在我们常用的前端分离开发中,通过JSON传递的过程是一个需要的类。

请求执行

具体执行就是通过反射,执行目标方法,详细的看参考资料。

参考资料:SpringMVC 九大组件之 HandlerAdapter 深入分析 - 掘金 (juejin.cn)

参数解析以及返回值解析

image.png

在前后端分离的通过JSON交互的过程中,例如:

image.png

这个参数的解析过程和返回值序列化时是个怎么的过程?

image.png

在执行RequestMappingHandlerAdapter.invokeHandlerMethod()方法中,把handlerMethod(其实就是上文中的返回的Handler)包装成一个ServletInocableHandlerMethod,然后给它设置上参数解析器集合和返回值处理器。

image.png

image.png

image.png

然后执行ServletInocableHandlerMethod.invokeAndHandle(),然后执行InvocableHandlerMethod.invokeForRequest(), 执行getMethodArgumentValues()方法。

image.png

这个方面主要的处理的事情:

  1. 检查解析器中是否支持这个参数
  2. 找到匹配的解析参数

然后再看一下这个HandlerMethodArgumentResolverComposite.resolveArgument()方法。

image.png

这个方法做的事情一个找到匹配的解析器,另一个是执行参数解析。举例中的参数解析就是RequestResponseBodyMethodProcessor

image.png

从这个类图可以看出,这个RequestResponseBodyMethodProcessor实现了HandlerMthodReturnValueHandlerHandlerMethodArgumentResolver接口,这个解析器支持@RequestBody @ResponseBody(@RestController) 注解。

image.png

image.png

image.png

最后调用到了父类AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters()方法。

image.png

image.png

这里面解析参数的关键代码主要是图上的这块,这里遍历HttpMessageConverter集合,寻找可以canRead这个参数的HttpMessageConverter(),这个用的MappingJackson2HttpMessageConverter,这个也可以替换成fastjson的HttpMessageConverter, 里面的具体执行过程这里没有详细研究。

在执行HttpMessageConverter.read()前后,会调用在初始化时,RequstMappingHandlerAdapter传给它的List<Object> requestResponseBodyAdvice,这里面存放的是实现了RequestBodyAdvice或者ResponseBodyAdvice的类,执行RequestBodyAdvice.beforeBodyRead()RequestBodyAdvice.afterBodyRead()方法。

image.png

在执行完成参数解析以及执行了invoke方法后,则返回ServletInocableHandlerMethod.invokeAndHandle()到继续HandlerMethodReturnValueHandlerComposite.handleReturnValue方法,

image.png

这个方法作用:

  • 查找HandlerMethodReturnValueHandler
  • 然后处理返回值

然后这里也是RequestResponseBodyMethodProcessor,因为它实现了HandlerMethodReturnValueHandler接口。

image.png

这里调用父类AbstractMessageConverterMethodProcessor.writeWithMessageConverters()方法,

image.png

在执行这段代码之前有一个内容协商机制,这个推荐看参考链接。在执行HttpMessageConvert之前也是会执行ResponseBodyAdvice.beforeBodyWrite()方法,然后执行HttpMessageConvert.write()

参考链接:spring boot2 (五)web中数据返回原理及内容协商 - 简书 (jianshu.com)

返回

image.png

在执行完handerlAdapter.handler之后,返回一个视图,这里对视图不分析了,返回json的话这里视图是个空对象,然后它会去在执行拦截器的applyPostHandle()方法,然后再执行processDispatchResult()方法,

image.png

这里面注意的地方就是对异常的统一处理,比如@ExecptionHandler修改的方法统一处理。

参考链接地址:SpringMVC 源码分析之 DispatcherServlet - 掘金 (juejin.cn)

总结

springMVC从配置初始化->DispatcherServlet初始化->请求执行->拦截器前置方法执行->参数解析->执行目标方法->返回值解析->返回视图->拦截器后置执行->(异常的处理),其中包含很多设计模式和组件。

设计模式:

  • 适配器
  • 执行链
  • 模板方法 等等

组件: HandlerMapping、 HandlerAdapter、HttpMessageConvter、RequestBodyAdvice、ResponseBodyAdvice、@ControllerAdvice、@ExecptionHandler、HandlerMethodArgumentResolver、HandlerMethodReturnValueHandler、HandlerInterceptor