一个http请求从客户端发起,经服务器处理后返回结果给客户端,本次聚焦于服务器处理过程,搞清楚SpringMvc处理请求的整个过程。

1.最开始的地方:Servlet

服务器接收到请求后由各种容器处理,如tomcat,这些容器在处理过程中会调用Servlet接口中的方法,由文档可知,在创建该类时会调用init方法,处理请求时会调用service方法,销毁时会调用destroy方法。
创建Servlet实例、调用生命周期方法的都是类似tomcat容器在处理请求过程中所做的事情,因此首先需要搞清楚的就是init和service到底干了些什么事。
image.png
首先来看下整个servlet的继承体系,其他的可能不熟悉,但是只要使用过SpringMvc的都会知道DispatcherServlet,很多文章会说这是web请求最开始的地方,其本质原因就是因为它继承了Servlet接口。
image.png
当容器启动时会进行初始化,此时会调用init方法,也就是调用实现类GenericServlet的init方法,该方法又会调用其子类的init方法
image.png
此方法中主要获取并设置了一些初始值,之后SpringBoot项目就会正式启动。
image.png

2.第一次请求到来时

在第一次发起请求时,依然会调用init方法,因为此时容器中很多组件都未初始化,只有在第一次请求时才会初始化
image.png
此时会调用FrameworkServlet的initServletBean方法,而控制台也会打印初始化日志
image.pngimage.png

2.1 initWebApplicationContext方法

因为initFrameworkServlet方法为空实现,因此核心逻辑都在initWebApplicationContext方法中,经过一系列判断后该方法最终会调用onRefresh方法
image.png
而FrameworkServlet中onRefresh方法为空实现,接着会调用子类DispatcherServlet的onRefresh方法,而该方法又会调用initStrategies方法,此方法中进行了所有初始化动作
image.png

2.2 initStrategies方法

initThemeResolver,initLocaleResolver,initMultipartResolver,initRequestToViewNameTranslator,initFlashMapManager这几个初始化方法类似,此处以initMultipartResolver为例讲解,首先它会在容器中获取名称为multipartResolver的实例,如果获取失败则会调用getDefaultStrategy方法获取默认值,multipartResolver默认是空的,因此没有调用此方法。
image.png
initHandlerMappings,initHandlerAdapters,initHandlerExceptionResolvers,initViewResolvers这几个方法首先会在容器中找到所有对应接口的实现类,然后对其进行排序,之后赋值给响应的属性变量。
image.png
至此整个初始化请求就算全部结束了,因此初始化过程主要分为两种,一种为只有一个实例的初始化方法,另一种为存在多个实例的初始化方法。

3.后续请求到来时

3.1 service方法

请求到来时容器会调用servlet的service方法进行处理,实际调用GenericServlet的子类HttpServet的service方法,
该方法内主要做了将ServletRequest和ServletReponse转为HttpServletRequest和HttpServletResponse。
image.png
强转完成后会调用同类中的重载方法进行请求处理,首先会获取到请求类型,根据类型的不同调用不同的方法进行处理,因此我们可以知道它支持的请求类型总共有:get、head、post、put、delete、options、trace、patch共8种
image.png
image.png
image.png
接着会调用子类的doGet方法,最后都会调用processRequest方法
image.png

3.2 processRequest方法

该方法初始化了ContextHolders之后就会调用doService方法,而此方法又会调用子类DispatcherServlet的方法
image.png
image.png

3.3 doService方法

该方法主要给request中放入了多个键值对,而其值为第一次请求时init方法初始化得到的,把值放入request中后会调用doDispatch方法。
image.png

3.4 doDispatch方法

根据文档描述可知,所有的http请求都会执行该方法,它会获取到第一个匹配的handler去执行,首先它会检查该请求是不是文件上传类型,即包含Multipart数据,之后会调用getHandler方法确定使用哪个handler进行处理,接着会调用getHandlerAdapter方法确定使用哪个handlerAdapte
image.png
之后回调用applyPreHandle方法执行拦截器
image.png
接着使用确定好的handleradapter执行handle方法,此方法会调用handleInternal方法

3.5 handleInternal和invokeHandlerMethod方法

此方法会调用invokeHandlerMethod方法,该方法首先获取数据绑定工厂和model工厂
image.png
之后判断参数解析器是否为空,不过不为空则进行参数解析,此处26个解析器就是我们在请求方法中可以使用的所有参数注解
image.png
紧接着会判断返回类型,如果返回类型解析器不为空则进行解析,此处的14个解析器就是我们在请求方法中可以返回的类型
image.png
之后就是业务代码的执行了,执行完成后会对返回值进行处理
image.png
因为在请求上标有requestbody注解,因此使用RequestResponseBodyMethodProcessor处理返回值
image.png
然后构建请求和响应消息,通过转换器将值写给客户端
image.png
首先会获取客户端可以接受的所有类型
image.png
最后经过一系列的计算后选择最合适的一种
image.png
之后在消息转换器中选择最合适的一个使用
image.png
之后调用applyPostHandle方法执行拦截器的postHandle方法,至此整个请求过程就已经全部结束了
image.png