Spring MVC 处理一个请求的流程

作者:程序员自由之路 时间:2021-12-19 18:39:39 

一个请求从客户端发出到达服务器,然后被处理的整个过程其实是非常复杂的。本博客主要介绍请求到达服务器被核心组件DispatcherServlet处理的整理流程(不包括Filter的处理流程)。

1. 处理流程分析

Servlet处理一个请求时会调用service()方法,所以DispatcherServlet处理请求的方式也是从service()方法开始(debug的话建议从DispatcherServlet的service方法开始debug)。FrameworkServlet重写了HttpServlet的service方法,这个service方法后面又调用了FrameworkServlet的processRequest()方法,processRequest()调用了DispatcherServlet的doService()方法,最后调用到DispatcherServlet的doDispatcher()方法。整合处理请求的方法调用流程如上,下面看下代码:


protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
processRequest(request, response);
}
else {
//这边调用了HttpServlet的service()方法,但由于FrameWorkServle重写了doGet、doPost等方法,所以最终还是会调用到processRequest方法
super.service(request, response);
}
}

再看看FrameworkServlet的processRequest()方法。


protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

long startTime = System.currentTimeMillis();
Throwable failureCause = null;

LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);

RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

initContextHolders(request, localeContext, requestAttributes);

try {
 //这边调用DispatcherServlet的doService()方法
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}

finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}

if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}

publishRequestHandledEvent(request, response, startTime, failureCause);
}
}

doService()方法的具体内容会在后面讲到,这边描述下doDispatcher()的内容,

首先根据请求的路径找到HandlerMethod(带有Method反射属性,也就是对应Controller中的方法),然后匹配路径对应的 * ,有了HandlerMethod和 * 构造个HandlerExecutionChain对象。HandlerExecutionChain对象的获取是通过HandlerMapping接口提供的方法中得到。有了HandlerExecutionChain之后,通过HandlerAdapter对象进行处理得到ModelAndView对象,HandlerMethod内部handle的时候,使用各种HandlerMethodArgumentResolver实现类处理HandlerMethod的参数,使用各种HandlerMethodReturnValueHandler实现类处理返回值。 最终返回值被处理成ModelAndView对象,这期间发生的异常会被HandlerExceptionResolver接口实现类进行处理。

总结下Spring MVC处理一个请求的过程:

  • 首先,搜索应用的上下文对象 WebApplicationContext 并把它作为一个属性(attribute)绑定到该请求上,以便控制器和其他组件能够使用它。

  • 将地区(locale)解析器绑定到请求上,以便其他组件在处理请求(渲染视图、准备数据等)时可以获取区域相关的信息。如果你的应用不需要解析区域相关的信息;

  • 将主题(theme)解析器绑定到请求上,以便其他组件(比如视图等)能够了解要渲染哪个主题文件。同样,如果你不需要使用主题相关的特性,忽略它即可如果你配置了multipart文件处理器,那么框架将查找该文件是不是multipart(分为多个部分连续上传)的。若是,则将该请求包装成一个 MultipartHttpServletRequest 对象,以便处理链中的其他组件对它做进一步的处理。关于Spring对multipart文件传输处理的支持;

  • 为该请求查找一个合适的处理器。如果可以找到对应的处理器,则与该处理器关联的整条执行链(前处理器、后处理器、控制器等)都会被执行,以完成相应模型的准备或视图的渲染如果处理器返回的是一个模型(model),那么框架将渲染相应的视图。若没有返回任何模型(可能是因为前后的处理器出于某些原因拦截了请求等,比如,安全问题),则框架不会渲染任何视图,此时认为对请求的处理可能已经由处理链完成了(这个过程就是doService()和doDispatcher()做的事情)

1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;

2、 DispatcherServlet——>HandlerMapping,HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor * )对象,通过这种策略模式,很容易添加新的映射策略;

3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;

4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);

5、 ModelAndView的逻辑视图名——> ViewResolver,ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;

6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;

7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。

2. 请求流程图

Spring MVC 处理一个请求的流程

还是这个图比较清楚。发现根据代码不太能把这个流程说清楚。而且整个流程很长,代码很多,我就不贴代码了。这里根据这个图再把整个流程中组件的功能总结下:

  • DispatcherServlet:核心控制器,所有请求都会先进入DispatcherServlet进行统一分发,是不是感觉有点像外观模式的感觉;

  • HandlerMapping:这个组件的作用就是将用户请求的URL映射成一个HandlerExecutionChain。这个HandlerExecutionChain是HandlerMethod和HandlerInterceptor的组合。Spring在启动的时候会默认注入很多HandlerMapping组件,其中最常用的组件就是RequestMappingHandlerMapping。

上面的HandlerMethod和HandlerInterceptor组件分别对应我们Controller中的方法和 * 。 * 会在HandlerMethod方法执行之前执行

  • HandlerAdapter组件,这个组件的主要作用是用来对HandlerMethod中参数的转换,对方法的执行,以及对返回值的转换等等。这里面涉及的细节就很多了,包括HandlerMethodArgumentResolver、HandlerMethodReturnValueHandler 、RequestResponseBodyMethodProcessor 、和HttpMessageConvert等组件。

当HandlerAdapter组件执行完成之后会得到一个ModleAndView组件,这个组件代表视图模型。

  • 得到ModleAndView后会执行 * 的postHandle方法。

  • 如果在上面的执行过程中发生任何异常,会由HandlerExceptionResolver进行统一处理。

  • 最后模型解析器会对上面的到的ModleAndView进行解析,得到一个一个View返回给客户端。在返回客户端之前还会执行 * 的afterCompletion方法。

来源:https://www.cnblogs.com/54chensongxia/p/12525418.html

标签:Spring,MVC,处理,请求
0
投稿

猜你喜欢

  • java rocketmq--消息的产生(普通消息)

    2023-10-19 08:51:50
  • SpringBoot中属性赋值操作的实现

    2022-05-04 18:10:30
  • java实现操作系统中的最佳置换Optimal算法

    2023-10-26 10:27:13
  • Java毕业设计实战之图片展览馆管理系统的实现

    2021-06-16 08:23:18
  • Android 实现永久保存数据的方法详解

    2023-06-23 22:13:23
  • SpringBoot解决跨域请求拦截问题代码实例

    2021-07-18 12:08:54
  • Java 动态数组的实现示例

    2022-02-27 07:05:25
  • java图片滑动验证(登录验证)原理与实现方法详解

    2023-07-10 13:29:53
  • Mybatis返回插入的主键问题解决方案

    2023-05-06 02:58:03
  • Java实现添加条形码到PDF表格的方法详解

    2023-04-26 12:37:25
  • Java如何设置系统参数和运行参数

    2023-12-19 10:47:01
  • 浅谈C#与Java两种语言的比较

    2023-09-26 13:05:19
  • Spring Security中使用authorizeRequests遇到的问题小结

    2023-10-07 04:23:45
  • Java提示缺少返回语句的解决办法

    2021-08-04 19:42:03
  • Java基础之面向对象机制(多态、继承)底层实现

    2023-11-12 02:59:59
  • IDEA(jetbrain通用)使用教程图解

    2023-04-15 04:05:49
  • Spring中@Scheduled和HttpClient的连环坑

    2023-10-19 23:06:00
  • spring boot加载第三方jar包的配置文件的方法

    2023-03-02 22:45:13
  • C#中SQL参数传入空值报错解决方案

    2023-12-14 14:28:59
  • java8 forEach结合Lambda表达式遍历 List操作

    2021-07-04 07:22:55
  • asp之家 软件编程 m.aspxhome.com