侧边栏壁纸
博主头像
再见理想博主等级

只争朝夕,不负韶华

  • 累计撰写 112 篇文章
  • 累计创建 64 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

SpringMVC之DispatcherServlet工作流程

再见理想
2022-06-08 / 0 评论 / 0 点赞 / 281 阅读 / 1,528 字

一,SpringMVC核心组件

Spring MVC 一共有九大核心组件,分别是:

  • MultipartResolver
  • LocaleResolver
  • ThemeResolver
  • HandlerMapping
  • HandlerAdapter
  • HandlerExceptionResolver
  • RequestToViewNameTranslator
  • ViewResolver
  • FlashMapManager

虽然很多,但是在前后端分离的架构中,最关键的只有 HandlerMapping + HandlerAdapter + HandlerExceptionResolver 。

二,DispatcherServlet工作流程

DispatcherServlet 的工作流程可以用一幅图来说明:

2.1,① 发送请求

用户向服务器发送 HTTP 请求,请求被 Spring MVC 的调度控制器 DispatcherServlet 捕获。

2.2,② 映射处理器

DispatcherServlet 根据请求 URL ,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 对象的形式返回。
即 HandlerExecutionChain 中,包含对应的 Handler 对象和拦截器们。

// HandlerMapping.java
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

2.3,③ 处理器适配

DispatcherServlet 根据获得的 Handler,选择一个合适的HandlerAdapter ,如果成功获得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(…) 方法。
提取请求 Request 中的模型数据,填充 Handler 入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:

  • HttpMessageConverter :会将请求消息(如 JSON、XML 等数据)转换成一个对象**。**
  • 数据转换:对请求消息进行数据转换。如 String 转换成 Integer、Double 等。
  • 数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等。
  • 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到 BindingResult 或 Error 中。

Handler(Controller) 执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象。

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

2.4,前后端分离架构

对于目前主流的架构,前后端已经进行分离了,所以 Spring MVC 只负责 Model 和 Controller 两块,而将 View 移交给了前端。所以,在上图中的步骤 ⑤ 和 ⑥ 两步,已经不在需要。
在步骤 ③ 中,如果 Handler(Controller) 执行完后,如果判断方法有 @ResponseBody 注解,则直接将结果写回给用户( 浏览器 )。
但是 HTTP 是不支持返回 Java POJO 对象的,所以需要将结果使用 HttpMessageConverter 进行转换后,才能返回。例如说,大家所熟悉的 FastJsonHttpMessageConverter ,将 POJO 转换成 JSON 字符串返回。

2.5,代码时序图

三,SpringMVC异常处理

Spring MVC 提供了异常解析器 HandlerExceptionResolver 接口,将处理器( handler )执行时发生的异常,解析并返回对应的 ModelAndView 结果。代码如下:

// HandlerExceptionResolver.java
public interface HandlerExceptionResolver {
    //解析异常,转换成对应的 ModelAndView 结果
    @Nullable
    ModelAndView resolveException(
        HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}

一般情况下,我们使用 @ExceptionHandler 注解来实现过异常的处理。

四,SpringMVC 优势

  1. 使用真的真的真的非常方便,无论是添加 HTTP 请求方法映射的方法,还是不同数据格式的响应。
  2. 提供拦截器机制,可以方便的对请求进行拦截处理。
  3. 提供异常机制,可以方便的对异常做统一处理。
  4. 可以任意使用各种视图技术,而不仅仅局限于 JSP ,例如 Freemarker、Thymeleaf 等等。
  5. 不依赖于 Servlet API (目标虽是如此,但是在实现的时候确实是依赖于 Servlet 的,当然仅仅依赖 Servlet ,而不依赖 Filter、Listener )。

五,SpringMVC 拦截器

org.springframework.web.servlet.HandlerInterceptor,拦截器接口。代码如下:

// HandlerInterceptor.java

/**
 * 拦截处理器,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 执行之前
 */
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	return true;
}

/**
 * 拦截处理器,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 执行成功之后
 */
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
		@Nullable ModelAndView modelAndView) throws Exception {
}

/**
 * 拦截处理器,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, 
 * Object)} 执行完之后,无论成功还是失败并且,只有该处理器
 * {@link #preHandle(HttpServletRequest, HttpServletResponse, Object)} 执行成功之后,才会被执行
 */
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
		@Nullable Exception ex) throws Exception {
}

一共有三个方法,分别为:

  • preHandle(…) 方法,调用 Controller 方法之执行,按拦截器定义顺序调用。若任一拦截器返回 false ,则 Controller 方法不再调用。
  • postHandle(…) 方法,调用 Controller 方法之执行,按拦截器定义逆序调用。
  • afterCompletion(…) 方法,处理完 Controller 方法返回结果之执行。 无论调用 Controller 方法是否成功,都会执行

SpringMVC 拦截器可以做什么?
拦截器能做的事情非常非常非常多,例如:

  • 记录访问日志;
  • 记录异常日志;
  • 需要登陆的请求操作,拦截未登陆的用户;

六,SpringMVC的HttpMessageConverter

HttpMessageConverter 是一种策略接口 ,它指定了一个转换器,它可以转换 HTTP 请求和响应。Spring REST 用这个接口转换 HTTP 响应到多种格式,例如:JSON 或 XML 。
每个 HttpMessageConverter 实现都有一种或几种相关联的MIME协议。Spring 使用 “Accept” 的标头来确定客户端所期待的内容类型。然后,它将尝试找到一个注册的 HTTPMessageConverter ,它能够处理特定的内容类型,并使用它将响应转换成这种格式,然后再将其发送给客户端。

如何创建 HttpMessageConverter 的自定义实现来支持一种新的请求/响应?
我们仅需要创建自定义的 AbstractHttpMessageConverter 的实现,并使用 WebMvcConfigurerAdapter 的 #extendMessageConverters(List<HttpMessageConverter<?>> converters) 方法注中册它,该方法可以生成一种新的请求 / 响应类型。
具体的示例,可以学习 《在 Spring 中集成 Fastjson》 文章。

0

评论区