一文读懂 spring MVC 请求处理流程(您值得拥有)

引言

springmvc 在web 项目中基本上是必用的,基于servlet的一种控制层框架,咱们在使用的过程当中每每会碰到各类问题,有时候尚未思绪解决问题,主要是由于咱们对请求处理的流程不熟悉,不能快速定位都问题所在,因此总会耗费大量时间,各类百度才解决问题。若是你也有这样的困惑,不妨一块儿来看下springmvc 的请求处理流程。让咱们可以快速定位问题。html

学习本场 Chat 您将了解到:web

  1. DispatcherServlet 九大对象介绍
  2. DispatcherServlet 核心方法分析
  3. request 请求处理流程分析
  4. 请求处理流程源码剖析

DispatcherServlet 九大组件

其中前面三个为核心组件。spring

  • HandlerMapping(处理器映射器)设计模式

    HandlerMapping 是⽤来查找 Handler 的,也就是处理器,具体的表现形式能够是类,也能够是⽅法。⽐如,标注了@RequestMapping的每一个⽅法均可以当作是⼀个Handler。Handler负责具体实际的请求处理,在请求到达后,HandlerMapping 的做⽤即是找到请求相应的处理器Handler 和 Interceptor.架构

  • HandlerAdapter(处理器适配器)mvc

    HandlerAdapter 是⼀个适配器。由于 Spring MVC 中 Handler 能够是任意形式的,只要能处理请求便可。可是把请求交给 Servlet 的时候,因为 Servlet 的⽅法结构都是doService(HttpServletRequest req,HttpServletResponse resp)形式的,要让固定的 Servlet 处理⽅法调⽤ Handler 来进⾏处理,即是 HandlerAdapter 的职责。app

  • ViewResolver框架

    ViewResolver即视图解析器,⽤于将String类型的视图名和Locale解析为View类型的视图,只有⼀个resolveViewName()⽅法。从⽅法的定义能够看出,Controller层返回的String类型视图名viewName 最终会在这⾥被解析成为View。View是⽤来渲染⻚⾯的,也就是说,它会将程序返回的参数和数据填⼊模板中,⽣成html⽂件。ViewResolver 在这个过程主要完成两件事情:ViewResolver 找到渲染所⽤的模板(第⼀件⼤事)和所⽤的技术(第⼆件⼤事,其实也就是找到视图的类型,如JSP)并填⼊参数。默认状况下,Spring MVC会⾃动为咱们配置⼀个InternalResourceViewResolver,是针对 JSP 类型视图的。jsp

  • HandlerExceptionResolversvg

    HandlerExceptionResolver ⽤于处理 Handler 产⽣的异常状况。它的做⽤是根据异常设置 ModelAndView,以后交给渲染⽅法进⾏渲染,渲染⽅法会将 ModelAndView 渲染成⻚⾯。

  • RequestToViewNameTranslator

    RequestToViewNameTranslator 组件的做⽤是从请求中获取 ViewName.由于 ViewResolver 根据ViewName 查找 View,但有的 Handler 处理完成以后,没有设置 View,也没有设置 ViewName,便要经过这个组件从请求中查找 ViewName。

  • LocaleResolver

    ViewResolver 组件的 resolveViewName ⽅法须要两个参数,⼀个是视图名,⼀个是 Locale。LocaleResolver ⽤于从请求中解析出 Locale,⽐如中国 Locale 是 zh-CN,⽤来表示⼀个区域。这个组件也是 i18n 的基础。

  • ThemeResolver

  • MultipartResolver

    MultipartResolver ⽤于上传请求,经过将普通的请求包装成 MultipartHttpServletRequest 来实现。MultipartHttpServletRequest 能够经过 getFile() ⽅法 直接得到⽂件。若是上传多个⽂件,还能够调⽤ getFileMap()⽅法获得Map<FileName,File>这样的结构,MultipartResolver 的做⽤就是封装普通的请求,使其拥有⽂件上传的功能。

  • FlashMapManager

    FlashMap ⽤于重定向时的参数传递,⽐如在处理⽤户订单时候,为了不重复提交,能够处理完 post 请求以后重定向到⼀个 get 请求,这个 get 请求能够⽤来显示订单详情之类的信息。这样作虽然能够规避⽤户从新提交订单的问题,可是在这个⻚⾯上要显示订单的信息,这些数据从哪⾥来得到呢?由于重定向时么有传递参数这⼀功能的,若是不想把参数写进URL(不推荐),那么就能够经过 FlashMap 来传递。只须要在重定向以前将要传递的数据写⼊请求(能够经过 ServletRequestAttributes.getRequest()⽅法得到)的属性OUTPUT_FLASH_MAP_ATTRIBUTE 中,这样在重定向以后的Handler中Spring就会⾃动将其设置到Model中,在显示订单信息的⻚⾯上就能够直接从Model中获取数据。FlashMapManager 就是⽤来管理 FalshMap 的。

这九大组件都在 DispatcherServlet 类中。

/** MultipartResolver used by this servlet. */
	// 多部件解析器
	@Nullable
	private MultipartResolver multipartResolver;

	/** LocaleResolver used by this servlet. */
	//地域解析器,国际化
	@Nullable
	private LocaleResolver localeResolver;

	/** ThemeResolver used by this servlet. */
	//主题解析器
	@Nullable
	private ThemeResolver themeResolver;

	/** List of HandlerMappings used by this servlet. */
	//处理器映射器组件
	@Nullable
	private List<HandlerMapping> handlerMappings;

	/** List of HandlerAdapters used by this servlet. */
	//处理器适配器组件
	@Nullable
	private List<HandlerAdapter> handlerAdapters;

	/** List of HandlerExceptionResolvers used by this servlet. */
	//处理器异常解析器
	@Nullable
	private List<HandlerExceptionResolver> handlerExceptionResolvers;

	/** RequestToViewNameTranslator used by this servlet. */
	//视图名称转换器
	@Nullable
	private RequestToViewNameTranslator viewNameTranslator;

	/** FlashMapManager used by this servlet. */
	//flash 组件管理器
	@Nullable
	private FlashMapManager flashMapManager;

	/** List of ViewResolvers used by this servlet. */
	//视图解析器
	@Nullable
	private List<ViewResolver> viewResolvers;

MVC 结构体系

三层架构:表现层、业务层和持久层

MVC 设计模式:

MVC 全名是 Model View Controller,是 模型(model)-视图(view)-控制器(controller) 的缩写, 是⼀

种⽤于设计建立 Web 应⽤程序表现层的模式。MVC 中每一个部分各司其职:

Model(模型):模型包含业务模型和数据模型,数据模型⽤于封装数据,业务模型⽤于处理业

务。

View(视图): 一般指的就是咱们的 jsp 或者 html。做⽤⼀般就是展现数据的。一般视图是依据

模型数据建立的。

Controller(控制器): 是应⽤程序中处理⽤户交互的部分。做⽤⼀般就是处理程序逻辑的。

MVC提倡:每⼀层只编写⾃⼰的东⻄,不编写任何其余的代码;分层是为了解耦,解耦是为了维

护⽅便和分⼯协做。

spring MVC 请求处理流程

全部请求都会经过DispatcherServlet 来执行。

流程说明:

一、DispatcherServlet 接收到客户端发送的请求。

二、DispatcherServlet 收到请求调用HandlerMapping 处理器映射器。

三、HandleMapping 根据请求URL 找到对应的handler 以及处理器 拦截器,返回给DispatcherServlet

四、DispatcherServlet 根据handler 调用HanderAdapter 处理器适配器。

五、HandlerAdapter 根据handler 执行处理器,也就是咱们controller层写的业务逻辑,并返回一个ModeAndView

六、HandlerAdapter 返回ModeAndView 给DispatcherServlet

七、DispatcherServlet 调用 ViewResolver 视图解析器来 来解析ModeAndView

八、ViewResolve 解析ModeAndView 并返回真正的view 给DispatcherServlet

九、DispatcherServlet 将获得的视图进行渲染,填充到request域中

十、返回给客户端响应结果。

springmvc 源码分析

请求进来。先找HttpServlet.发现FrameworkServlet 重现了doGet()和doPost() 方法。因此会执行其中的方法。

image-20200610155343088

而且在FrameworkServlet 中实现了HttpServlet 的 doGet()和doPost() 方法。

image-20200610155417563

咱们接着看FrameworkServlet 的doGet和doPost 方法都是调用其processRequest 方法。这个方法里面主要的调用DispatcherServlet中doService()方法。

image-20200610160254087

在DispatcherServlet 中的这个方法。会调用doDispatche() 方法执行。

image-20200610160509049

image-20200610160104711

因此总体的请求流程都在doDispatch() 方法中。

主要流程以下:

一、根据url 请求获取到handlerExecutorChina 对象,也就是获取到handler执行链对象,这个对象中包含执行的handler 和一个拦截器的集合。

image-20200611154006184

image-20200611154037844

二、根据这个handlerExecutorChina 执行链对象获取到对应的handlerAdapter handler适配器。

三、根据这个适配器,真正执行handler ,而且返回一个modeAndView 这里的handler 就是咱们一般全部的controller 层的业务逻辑。

image-20200611154638816

四、根据获取到的modeAndView ,解析渲染页面并返回结果。

image-20200611160300399

这样总体核心流程就完了。只有这四步。其实和最开始的流程处理图是同样的。总结一下:先根据请求从handlermapping 中获取到handle ,而后经过handle 找到能处理该请求的 handlerAdapter ,经过handlerAdapter 执行真正的handler 也就是咱们的业务代码,并返回一个 ModeAndView 。而后经过viewResolver 解析成view 返回给页面

九大组件初始化的流程

九大组件初始化是在 DispatcherServlet 中的onRefresh() 方法中。

image-20200611161600286

咱们经过调用栈能够发现,是在applicationContext类中的refresh() 方法中执行的。这个方法咱们很熟悉就是spring 框架的初始化流程执行的主要方法。在refresh() 方法中 完成的Bean 对象实例化流程以后,会执行事件发布。这样就来到了咱们springmvc 初始化了。

这九大组件的初始化流程都是差很少的,咱们来看下核心组件的HandlerMapping 组件的初始化。

先在ApplicationContext中查找全部HandlerMappings,包括祖先上下文 活着指定的名称还获取,若是获取不到,就会从默认的配置中获取handlermappings

image-20200611163342283

获取默认的handlermappings 主要是从defaultStrategies 中获取。

那defaultStrategies 数据是怎么来的呢?

能够看到这个Properties 是从DispatcherServlet.properties 配置文件来的。

image-20200611164132953

咱们查看这个问价能够看到默认的配置信息,九大组件的默认配置信息都有。

获取Handler 流程

下面咱们回到主流程,第一步,从handlermappingshandlerMappings 中获取对应的handler

image-20200611164923494

能够看到就是遍历handlerMappings 找到这个url 对应的handler 就完了。

获取handlerAdapter 流程

同样的遍历handlerAdpters ,获取到能够处理这个handler 的适配器。

ha.handler() 执行真正的处理器流程

image-20200611170202252

image-20200611170222629

image-20200611170451679

image-20200611171336268

能够根据调用栈很好的找到调用流程。主要就是检测request ,而后经过url 找到队对应的方法,填充方法须要的参数值,经过反射调用该方法。

processDispatchResult 处理流程

render⽅法完成渲染

image-20200611172123379

image-20200611172201908

视图解析器解析出View视图对象

image-20200611172219756

二、在解析出View视图对象的过程当中会判断是否重定向、是否转发等,不一样的状况封装的是不一样的View实现

三、解析出View视图对象的过程当中,要将逻辑视图名解析为物理视图名

四、封装View视图对象以后,调⽤了view对象的render⽅法

五、渲染数据

六、把modelMap中的数据暴露到request域中,这也是为何后台model.add以后在jsp中能够从请求域取出来的根本缘由

七、将数据设置到请求域中

总结

主要了解请求处理的流程,在 DispatcherServlet 中,先经过请求从handlerMappings 中获取对应的handler ,而后经过handler 找到对应的 handlerAdapter 而后经过handlerAdapter 的handle() 方法真正执行我么controller 层的业务逻辑。并返回一个 ModeAndView 而后经过 ViewResolver 解析成view 并渲染到界面上。

固然这中间还有拦截器,主要在获取 handlerAdapter 后,会先执行拦截器方法,而后才执行真正的handler 方法。

若是您以为好看,记得给我点个赞喔!!!

若是您以为好看,记得给我点个赞喔!!!

若是您以为好看,记得给我点个赞喔!!!