SpringMVC源码深度解析

目录

SpringMVC的三大组件

DispatcherServlet:前端控制器

HandlerMapping:处理器映射器

HandlerExecutionChain:处理器执行链

Handler:处理器

HandlerAdapter:处理器适配器

ModelAndView:模型和视图

ViewResolver:视图解析器

View:视图

HandlerExceptionResolver:处理器异常解析器

HttpMessageConverter:http报文转换器

处理流程:源码解析

请求到达入口:doDispatch

①:解析 multipart 类型的请求

②:根据请求获取 HandlerExecutionChain 对象

③:根据处理器获取 HandlerAdapter

④:调用拦截器的 preHandle 方法

⑤:调用 handler 实际处理请求,获取 ModelAndView 对象

⑥:调用拦截器的 postHandle 方法

⑦:渲染视图

处理流程:纯文字描述


SpringMVC的三大组件

DispatcherServlet:前端控制器

这是大家是最熟悉的,是一个 servlet,是 springmvc 处理请求的入口,不需要咱们开发,由框架提供。

作用:统一处理请求和响应,整个流程控制的中心,由它来调用其他组件处理用户的请求。

HandlerMapping:处理器映射器

作用:根据请求的信息(如 url、method、header 等)查找请求处理器,即找到自定义的 controller 中处理请求的方法。

HandlerMapping 接口源码如下,getHandler:根据请求查找请求处理器,会返回一个 HandlerExecutionChain 对象。

public interface HandlerMapping {
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

常见的实现类:

  • RequestMappingHandlerMapping:请求映射处理器映射,用来处理@RequestMapping 定义的处理器的

HandlerExecutionChain:处理器执行链

HandlerMapping#getHandler 方法会根据请求得到一个 HandlerExecutionChain 对象。

HandlerExecutionChain 源码如下,主要包含了 3 个信息

  • handler:请求处理器,通常就是我们自定义的 controller 对象及方法

  • interceptorList:拦截器,当前请求匹配到的拦截器列表

  • interceptorIndex:拦截器索引,用来记录执行到第几个拦截器了

public class HandlerExecutionChain {

 private final Object handler;

 private final List<HandlerInterceptor> interceptorList = new ArrayList<>();

 private int interceptorIndex = -1;

}

Handler:处理器

通常需要我们自己开发,一般指我们自定义的 controller,在 DispatcherServlet 的控制下 handler 对具体的请求进行处理。

HandlerAdapter:处理器适配器

他负责对 handler 的方法进行调用,由于 handler 的类型可能有很多种,每种 handler 的调用过程可能不一样,此时就需要用到适配器 HandlerAdapte,适配器对外暴露了统一的调用方式(见其 handle 方法),内部将 handler 的调用过程屏蔽了,HandlerAdapter 接口源码如下,主要有 2 个方法需要注意:

  • supports:当前 HandlerAdapter 是否支持 handler,其内部主要就是判 HandlerAdapter 是否能够处理 handler 的调用

  • handle:其内部负责调用 handler 的来处理用户的请求,返回返回一个 ModelAndView 对象

public interface HandlerAdapter {

 boolean supports(Object handler);

 @Nullable
 ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

}

常见的实现类:

  • RequestMappingHandlerAdapter:其内部用来调用@RequestMapping 标注的方法

ModelAndView:模型和视图

这个对象中主要用来存放视图的名称和共享给客户端的数据。

public class ModelAndView {

 /*视图*/
 @Nullable
 private Object view;

 /*模型,用来存放共享给客户端的数据*/
 @Nullable
 private ModelMap model;

}

ViewResolver:视图解析器

这个是框架提供的,不需要咱们自己开发,它负责视图解析,根据视图的名称得到对应的视图对象(View)。

ViewResolver 接口源码

public interface ViewResolver {

 @Nullable
 View resolveViewName(String viewName, Locale locale) throws Exception;

}

这个接口有很多实现类,比如 jsp 的、freemarker、thymeleaf 的等,他们都有各自对应的 ViewResolver。

而比较常的实现类是InternalResourceViewResolver,这个大家应该比较熟悉吧,目前为止我们前面的文章用到的都是这个视图解析器,用来处理 jsp 格式的视图页面,带大家再回顾一下这个类的配置,如下

<!-- 添加视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/view/"/>
    <property name="suffix" value=".jsp"/>
</bean>

InternalResourceViewResolver 比较重要,这里说下这个类的 resolveViewName 方法获取视图的过程,大家也可以去阅读InternalResourceViewResolver#resolveViewName方法获得,大致的过程如下:

step1:判断视图 viewName 是否以redirect:开头,如果是,则返回RedirectView类型的视图对象,RedirectView 是用来重定向的,RedirectView 内部用到的是response.sendRedirect(url)进行页面重定向;否则继续向下 step2

step2:判断 viewName 是否以forward:开头,如果是,则返回InternalResourceView类型的视图对象,InternalResourceView 是用来做跳转的,InternalResourceView 内部用到的是request.getRequestDispatcher(path).forward(request, response)进行页面跳转;否则继续向下 step3

step3:判断当前项目是否存在 jstl 所需的类,如果是,则返回 JstlView 类型的视图,否则返回 InternalResourceView 类型的视图,这两个视图的 render 方法最终会通过request.getRequestDispatcher(path).forward(request, response)进行页面的跳转,跳转的路径是:InternalResourceViewResolver 的前缀 prefix + viewName+InternalResourceViewResolver 的后缀 prefix

View:视图

负责将结果展示给用户,View 接口源码如下,render 方法根据指定的模型数据(model)渲染视图,即 render 方法负责将结果输出给客户端。

public interface View {
 void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
   throws Exception;
}

View 接口常见的 2 个实现类

  • RedirectView:负责重定向的,内部通过response.sendRedirect(url)进行页面重定向

  • InternalResourceViewResolver:负责页面跳转的,内部通过request.getRequestDispatcher(path).forward(request, response)进行页面的跳转

HandlerExceptionResolver:处理器异常解析器

负责处理异常的,HandlerExceptionResolver 接口有个resolveException方法,用来解析异常,返回异常情况下对应的 ModelAndView 对象

public interface HandlerExceptionResolver {

 @Nullable
 ModelAndView resolveException(
   HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);

}

HttpMessageConverter:http报文转换器

将请求报文转换为 Java 对象,或将 Java 对象转换为响应报文,在处理@RequestBody、RequestEntity、@ResponseBody、ResponseEntity 的时候会用到

public interface HttpMessageConverter<T> {

 /**
  * 是否可以将请求报文读取给方法参数指定的类型
  */
 boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

 /**
  * 是否可以将响应的报文转换为方法参数指定的类型输出
  */
 boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

 /**
  * 当前转换器支持的类型
  */
 List<MediaType> getSupportedMediaTypes();

 /**
  * 当前转换器支持的类型
  */
 default List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
  return (canRead(clazz, null) || canWrite(clazz, null) ?
    getSupportedMediaTypes() : Collections.emptyList());
 }

 /**
  * 将http报文转换为给定的类型,然后返回
  */
 T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
   throws IOException, HttpMessageNotReadableException;

 /**
  * 将给定的对象t,转换为http报文输出到客户端
  */
 void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
   throws IOException, HttpMessageNotWritableException;

}

处理流程:源码解析

请求到达入口:doDispatch

springmvc 的所有请求,最终都会到达org.springframework.web.servlet.DispatcherServlet#doDispatch这个方法,整个请求的大致处理过程都在这个方法中,咱们从这个方法开始分析࿰

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰魄雕狼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值