前言
自己学习总结和整理的,内容可能有错误,还望多多指教
springmvc执行流程图
springboot加载spring mvc配置
servlet3.0的规范,spring通过实现ServletContainerInitializer接口,重写了onStartup,这里spring重写了onStartUp方法,传入所有实现了WebApplicationInitializer接口,实现了类似web.xml这样的初始化配置
参考地址:docs.spring.io/spring-fram…
spring mvc 初始化
spring mvc初始化主要是HttpServietBean、FrameworkServlet和DispatcherServlet, HttpServietBean负责加载Servlet配置,FrameworkServlet负责WebApplicationContext初始化,DispatcherServlet负责初始化HandlerMapping、HanlerAadapter等组件。在springboot-web,整个初始化过程是懒加载,当应用的第一个请求进来时在开始初始化。
参考链接:SpringMVC 初始化流程分析 - 掘金 (juejin.cn)
执行过程
DispatcherServlet
请求进来之后,先执行FrameworkServlet.processRequest方法,
在这个方法中,有几点关注
- localeContext 是本地化一些配置,LocaleContextHolder维护了一个ThreadLocal来保存这个,我们在当前线程的任何方法里可以直接调用LocaleContextHolder获得localeContext。
- RequestContextHolder和1的用户一样,里面两个ThreadLocal,保存了RequestAttributes。
- 释放LocaleContextHolder和RequestContextHolder
- 发布一个请求结束的事件,我们可以监听这个事件
调用doService方法,主要是配置一些属性等等,主要看doDispatch方法
调用getHandler获得HandlerExceutionChain(处理器执行链)。
HandlerMapping的作用就是根据request找到相应的处理器Handler和Interceptors(拦截器),上图可以看到HandlerMapping有很多实现类,主要关注一下日常开发常用的@Controller @RequestMapping方式。
AbstractHandlerMapping
所有的HandlerMapping都是继承自AbstractHandlerMapping,首先看一下这个类型的初始化方法
主要是用来初始化拦截器(实现HandlerInterceptor接口)的。
- 获取handler,这个是由子类来实现的
- 添加拦截器
- 处理跨域
AbstractHandlerMethodMapping
这个类的体系下有三个类,AbstractHandlerMethodMapping、RequestMappingInfoHandlerMapping、RequestMappingHandlerMapping。其他的Handler一个类代表一个handler,而@RequestMapping这种一个方法代表一个handler。
初始化,AbstractHandlerMethodMapping实现了InitializingBean接口(是spring bean初始化三种实现方式),主要是找到使用了@controller, @requestmapping这几个注解的bean,然后找到bean中的method,根据请求路径,放入一个HashMap的缓存中。
获取Handler,根据request的请求路径,取mappingRegistry中匹配一个适合的HandlerMethod,返回返回。
详细过程参考:SpringMVC 九大组件之 HandlerMapping 深入分析 - 掘金 (juejin.cn)
HandlerAdapter
SpringMVC拿到具体HandlerAdapter来具体执行方法,这里用到适配器模式,不同的Handler的具体执行方式也不同,这里就需要HandlerAdapter。
在执行HandlerAdapter之前,需要执行拦截器的preHandle方法。
HandlerAdapter有很多类型,但是这里主要关注的是RequestMappingHandlerAdapter,它的父类AbstractHandlerMethodAdapter实现了HandlerAdapter接口,但是具体集体方法都交给了子类去实现。
RequestMappingHandlerAdapter
初始化
RequestMappingHandlerAdapter 实现了InitializingBean接口,在初始化中做的事情是:
- 查找所有标记了
@ControllerAdvice注解的Bean,保存起来;在这里类中找到方法标注了@ModelAttribute, 缓存起来;在这些类中找到方法标注了@InitBinder,缓存起来; 查找实现了RequestBodyAdvice或者ResponseBodyAdvice的类,然后缓存起来。
2、3、4主要是对argumentResolvers(参数解析器)、initBinderArgumentResolvers、returnValueHandlers(返回处理器)进行初始化。
上面这些都可以进行自定义扩展,详细的可以看参考资料。这里需要注意一个RequestResponseBodyMethodProcessor类,这个在我们常用的前端分离开发中,通过JSON传递的过程是一个需要的类。
请求执行
具体执行就是通过反射,执行目标方法,详细的看参考资料。
参考资料:SpringMVC 九大组件之 HandlerAdapter 深入分析 - 掘金 (juejin.cn)
参数解析以及返回值解析
在前后端分离的通过JSON交互的过程中,例如:
这个参数的解析过程和返回值序列化时是个怎么的过程?
在执行RequestMappingHandlerAdapter.invokeHandlerMethod()方法中,把handlerMethod(其实就是上文中的返回的Handler)包装成一个ServletInocableHandlerMethod,然后给它设置上参数解析器集合和返回值处理器。
然后执行ServletInocableHandlerMethod.invokeAndHandle(),然后执行InvocableHandlerMethod.invokeForRequest(), 执行getMethodArgumentValues()方法。
这个方面主要的处理的事情:
- 检查解析器中是否支持这个参数
- 找到匹配的解析参数
然后再看一下这个HandlerMethodArgumentResolverComposite.resolveArgument()方法。
这个方法做的事情一个找到匹配的解析器,另一个是执行参数解析。举例中的参数解析就是RequestResponseBodyMethodProcessor。
从这个类图可以看出,这个RequestResponseBodyMethodProcessor实现了HandlerMthodReturnValueHandler和HandlerMethodArgumentResolver接口,这个解析器支持@RequestBody 和 @ResponseBody(@RestController) 注解。
最后调用到了父类AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters()方法。
这里面解析参数的关键代码主要是图上的这块,这里遍历HttpMessageConverter集合,寻找可以canRead这个参数的HttpMessageConverter(),这个用的MappingJackson2HttpMessageConverter,这个也可以替换成fastjson的HttpMessageConverter, 里面的具体执行过程这里没有详细研究。
在执行HttpMessageConverter.read()前后,会调用在初始化时,RequstMappingHandlerAdapter传给它的List<Object> requestResponseBodyAdvice,这里面存放的是实现了RequestBodyAdvice或者ResponseBodyAdvice的类,执行RequestBodyAdvice.beforeBodyRead() 和 RequestBodyAdvice.afterBodyRead()方法。
在执行完成参数解析以及执行了invoke方法后,则返回ServletInocableHandlerMethod.invokeAndHandle()到继续HandlerMethodReturnValueHandlerComposite.handleReturnValue方法,
这个方法作用:
- 查找HandlerMethodReturnValueHandler
- 然后处理返回值
然后这里也是RequestResponseBodyMethodProcessor,因为它实现了HandlerMethodReturnValueHandler接口。
这里调用父类AbstractMessageConverterMethodProcessor.writeWithMessageConverters()方法,
在执行这段代码之前有一个内容协商机制,这个推荐看参考链接。在执行HttpMessageConvert之前也是会执行ResponseBodyAdvice.beforeBodyWrite()方法,然后执行HttpMessageConvert.write()。
参考链接:spring boot2 (五)web中数据返回原理及内容协商 - 简书 (jianshu.com)
返回
在执行完handerlAdapter.handler之后,返回一个视图,这里对视图不分析了,返回json的话这里视图是个空对象,然后它会去在执行拦截器的applyPostHandle()方法,然后再执行processDispatchResult()方法,
这里面注意的地方就是对异常的统一处理,比如@ExecptionHandler修改的方法统一处理。
参考链接地址:SpringMVC 源码分析之 DispatcherServlet - 掘金 (juejin.cn)
总结
springMVC从配置初始化->DispatcherServlet初始化->请求执行->拦截器前置方法执行->参数解析->执行目标方法->返回值解析->返回视图->拦截器后置执行->(异常的处理),其中包含很多设计模式和组件。
设计模式:
- 适配器
- 执行链
- 模板方法 等等
组件:
HandlerMapping、 HandlerAdapter、HttpMessageConvter、RequestBodyAdvice、ResponseBodyAdvice、@ControllerAdvice、@ExecptionHandler、HandlerMethodArgumentResolver、HandlerMethodReturnValueHandler、HandlerInterceptor等