其他分享
首页 > 其他分享> > 面试官:小伙子,你画的SpringMVC请求处理过程是从网上抄的吧?

面试官:小伙子,你画的SpringMVC请求处理过程是从网上抄的吧?

作者:互联网

  推荐学习肝了十天半月,献上纯手绘“Spring/Cloud/Boot/MVC”全家桶脑图 消息中间件合集:MQ(ActiveMQ/RabbitMQ/RocketMQ)+Kafka+笔记 前言

  SpringMVC请求处理相信大家都很熟悉了,本篇主要是基于SpringMVC处理请求的流程来阅读并调试源码,以及解决几个仅靠流程图无法解释的问题。

  本篇使用的Spring版本为5.2.2.RELEASE

  九大组件

  SpringMVC几乎所有的功能都由九大组件来完成,所以明白九大组件的作用,对于学习SpringMVC来说非常重要。

  /** 文件上传解析器 */

  private MultipartResolver multipartResolver;

  /** 区域解析器,用于国际化 */

  private LocaleResolver localeResolver;

  /** 主题解析器 */

  private ThemeResolver themeResolver;

  /** Handler映射信息 */

  private List handlerMappings;

  /** Handler适配器*/

  private List handlerAdapters;

  /** Handler执行异常解析器 */

  private List handlerExceptionResolvers;

  /** 请求到视图的转换器 */

  private RequestToViewNameTranslator viewNameTranslator;

  /** SpringMVC允许重定向时携带参数,存在session中,用完就销毁,所以叫FlashMap */

  private FlashMapManager flashMapManager;

  /** 视图解析器 */

  private List viewResolvers;

  1234567891011121314151617181920212223242526HandlerMapping:Handler映射信息,根据请求携带的url信息查找处理器(Handler)。每个请求都需要对应的Handler处理。HandlerAdapter:Handler适配器,SpringMVC没有直接调用处理器(Handler),而是通过HandlerAdapter来调用,主要是为了统一Handler的调用方式ViewResolver:视图解析器,用来将字符串类型的视图名称解析为View类型的视图。ViewResolver需要找到渲染所用的模板和所用的技术(也就是视图的类型)进行渲染,具体的渲染过程则交由不同的视图自己完成。MultipartResolver:文件上传解析器,主要用来处理文件上传请求HandlerExceptionResolver:Handler执行异常解析器,用来对异常进行统一处理RequestToViewNameTranslator:请求到视图的转换器LocaleResolver:区域解析器,用于支持国际化FlashMapManager:SpringMVC允许重定向时携带参数,存在session中,用完就销毁,所以叫FlashMapThemeResolver:主题解析器,用于支持不同的主题

  九大组件中最重的的前三个,HandlerMapping、HandlerAdapter和ViewResolver,因为这是阅读源码时,避不开的三个组件。

  调试准备

  搭建一个基本的Spring web项目即可

  Controller部分

  @Controller

  public class IndexController {

  @RequestMapping("/index/home")

  public String home(String id, Student student, @RequestParam("code") String code) {

  System.out.println(student.getName());

  return "index";

  }

  @ResponseBody

  @RequestMapping("/index/list")

  public String list() {

  return "success";

  }

  }

  Entity部分

  public class Student {

  private String name;

  private Integer gender;

  // getter、setter

  }

  还是那句话,Spring源码非常庞大,不能只见树木不见森林,需要有针对性的阅读,所以本篇只需要关注主体流程即可。

  核心方法

  我们都知道,SpringMVC有一个用来分发请求的前端控制器DispatcherServlet,其中用来处理请求的方法就是doService,该方法定义如下

  doService

  /**

  * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}

  * for the actual dispatching.

  */

  @Override

  protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

  logRequest(request);

  // Keep a snapshot of the request attributes in case of an include,

  // to be able to restore the original attributes after the include.

  Map<String, Object> attributesSnapshot=null;

  if (WebUtils.isIncludeRequest(request)) {

  attributesSnapshot=new HashMap<>();

  Enumeration<?> attrNames=request.getAttributeNames();

  while (attrNames.hasMoreElements()) {

  String attrName=(String) attrNames.nextElement();

  if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {

  attributesSnapshot.put(attrName, request.getAttribute(attrName));

  }

  }

  }

  // Make framework objects available to handlers and view objects.

  request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());

  request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);

  request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);

  request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

  if (this.flashMapManager !=null) {

  FlashMap inputFlashMap=this.flashMapManager.retrieveAndUpdate(request, response);

  if (inputFlashMap !=null) {

  request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));

  }

  request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());

  request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

  }

  try {

  // 真正执行的方法

  doDispatch(request, response);

  }

  finally {

  if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {

  // Restore the original attribute snapshot, in case of an include.

  if (attributesSnapshot !=null) {

  restoreAttributesAfterInclude(request, attributesSnapshot);

  }

  }

  }

  }doDispatch

  doDispatch是doService中真正用来处理请求的方法

  /**

  * 实际处理请求的方法

  */

  protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

  HttpServletRequest processedRequest=request;

  HandlerExecutionChain mappedHandler=null;

  boolean multipartRequestParsed=false;

  WebAsyncManager asyncManager=WebAsyncUtils.getAsyncManager(request);

  try {

  ModelAndView mv=null;

  Exception dispatchException=null;

  try {

  // 校验是否是文件上传请求

  processedRequest=checkMultipart(request);

  multipartRequestParsed=(processedRequest !=request);

  // Determine handler for the current request.

  // 为当前请求找到一个合适的处理器(Handler)

  // 返回值是一个HandlerExecutionChain,也就是处理器执行链

  mappedHandler=getHandler(processedRequest);

  if (mappedHandler==null) {

  noHandlerFound(processedRequest, response);

  return;

  }

  // Determine handler adapter for the current request.

  // 根据HandlerExecutionChain携带的Handler找到合适的HandlerAdapter

  HandlerAdapter ha=getHandlerAdapter(mappedHandler.getHandler());

  // Process last-modified header, if supported by the handler.

  // 处理GET请求的缓存

  String method=request.getMethod();

  boolean isGet="GET".equals(method);

  if (isGet || "HEAD".equals(method)) {

  long lastModified=ha.getLastModified(request, mappedHandler.getHandler());

  if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {

  return;

  }

  }

  // 执行拦截器的preHandle方法

  if (!mappedHandler.applyPreHandle(processedRequest, response)) {

  return;

  }

  // Actually invoke the handler.

  // 利用HandlerAdapter来执行Handler里对应的处理方法

  mv=ha.handle(processedRequest, response, mappedHandler.getHandler());

  if (asyncManager.isConcurrentHandlingStarted()) {

  return;

  }

  // 如果没有设置视图,则应用默认的视图名

  applyDefaultViewName(processedRequest, mv);

  // 执行拦截器的postHandle方法

  mappedHandler.applyPostHandle(processedRequest, response, mv);

  }

  catch (Exception ex) {

  dispatchException=ex;

  }

  catch (Throwable err) {

  // As of 4.3, we're processing Errors thrown from handler methods as well,

  // making them available for @ExceptionHandler methods and other scenarios.

  dispatchException=new NestedServletException("Handler dispatch failed", err);

  }

  // 根据ModelAndView对象解析视图

  processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

  }

  catch (Exception ex) {

  triggerAfterCompletion(processedRequest, response, mappedHandler, ex);

  }

  catch (Throwable err) {

  triggerAfterCompletion(processedRequest, response, mappedHandler,

  new NestedServletException("Handler processing failed", err));

  }

  finally {

  if (asyncManager.isConcurrentHandlingStarted()) {

  // Instead of postHandle and afterCompletion

  if (mappedHandler !=null) {

  mappedHandler.applyAfterConcurrentHandlingStarted(proc

标签:面试官,处理过程,SpringMVC,mappedHandler,request,视图,Handler,response,processedRequest
来源: https://www.cnblogs.com/linjingyg/p/15687374.html