Spring MCV源码分析(二) DispatcherServlet的生命周期

一.DispatcherServlet简述

DispatcherServletSpring MVC框架中的前端控制器,通过调度其他组件来处理用户的请求,因此可以说它是Spring MVC中最核心的部分。

二.分析思路

在分析前,我们应该首先明确分析的思路和过程。从名字中我们可以很容易知道,DispatcherServlet首先是一个Servlet,因此它被配置在web.xml文件中。而我们分析一个Sevlet,通常的思路应当是顺着其生命周期分析。
– init方法
– service方法
– destory方法

三.init方法

1. 找到init方法
直接在DispatcherServlet中并没有找到init()方法,但是发现该类继承自其他类,这是它的继承关系图。

通过向父类中寻找可以发现是HttpServletBean这个类重写了init方法,跳转到HttpServletBean这个类中

2. init方法剖析
– 源码展示

public final void init() throws ServletException {
  if (logger.isDebugEnabled()) {
   logger.debug("Initializing servlet '" + getServletName() + "'");
  }
  try {
   PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
   BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
   ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
   bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
   initBeanWrapper(bw);
   bw.setPropertyValues(pvs, true);
  }
  catch (BeansException ex) {
   logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
   throw ex;
  }
  initServletBean();
  if (logger.isDebugEnabled()) {
   logger.debug("Servlet '" + getServletName() + "' configured successfully");
  }
 }

这个方法和核心涉及到三个类,PropertyValues,BeanWrapper,和ResourceLoader,因此我们应该分别分析这三个类的实例对象在该方法起到的作用

  • PropertyValues
    PropertyValues是HttpServletBean的一个内部类,继承了MutablePropertyValues,用来获取web.xml中的属性如contextConfigLocation

  • BeanWrapper
    BeanWrapper封装了bean的行为,提供了设置和获取属性值。

  • ResourceLoader
    ResourceLoader用来获取spring mvc配置文件的信息

先通过PropertyValues获取web.xml文件init-param的参数值,然后通过ResourceLoader读取.xml配置信息,BeanWrapper对配置的标签进行解析和将系统默认的bean的各种属性设置到对应的bean属性

注意到第17行的initServletBean()方法,这是一个抽象方法,在源代码中作者的注释为Let subclasses do whatever initialization they like.即要求子类实现这个方法去完成子类还需要的其他初始化操作,通过代码的跟踪,我们可以在DispatcherSevlet方法中找到一个方法为initStrategies(),这个方法就是子类为初始化工作编写的代码,该方法代码如下。

protected void initStrategies(ApplicationContext context) {
  initMultipartResolver(context);
  initLocaleResolver(context);
  initThemeResolver(context);
  initHandlerMappings(context);
  initHandlerAdapters(context);
  initHandlerExceptionResolvers(context);
  initRequestToViewNameTranslator(context);
  initViewResolvers(context);
  initFlashMapManager(context);
 }
  • 一开始我们说到DispatcherServlet是通过调度其他组件来处理请求的,因此该类必定要对那些组件进行初始化,而这段代码就是进行这样的工作的。我们从此也可以知道DispatcherServlet依赖了什么组件。
    • MultipartResolver
    • LocaleResolver
    • ThemeResolver
    • HandlerMappings
    • HandlerAdapters
    • HandlerExceptionResolvers
    • RequestToViewNameTranslator
    • ViewResolvers
    • FlashMapManager

四.Service方法

在Servlet中,每个请求都会被对应的Servlet类中的service方法处理,在DispatcherServlet中,service的实现在其父类FrameworkServlet

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

  String method = request.getMethod();
  if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
   processRequest(request, response);
  }
  else {
   super.service(request, response);
  }
 }

其核心的方法是processRequest(request, response);

 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 {
   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, startTime, failureCause);
  }
 }

这个方法执行的核心方法为doService,doService是一个抽象方法,在DispatcherServlet中实现

 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  if (logger.isDebugEnabled()) {
   String requestUri = urlPathHelper.getRequestUri(request);
   String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
   logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
     " processing " + request.getMethod() + " request for [" + requestUri + "]");
  }

  // 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)) {
   logger.debug("Taking snapshot of request attributes before include");
   attributesSnapshot = new HashMap<String, Object>();
   Enumeration<?> attrNames = request.getAttributeNames();
   while (attrNames.hasMoreElements()) {
    String attrName = (String) attrNames.nextElement();
    if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
     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());

  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()) {
    return;
   }
   // Restore the original attribute snapshot, in case of an include.
   if (attributesSnapshot != null) {
    restoreAttributesAfterInclude(request, attributesSnapshot);
   }
  }
 }

但是控制器和拦截器的代码是在doDispach()中执行的

 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;
    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null || mappedHandler.getHandler() == null) {
     noHandlerFound(processedRequest, response);
     return;
    }
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    String method = request.getMethod();
    boolean isGet = "GET".equals(method);
    if (isGet || "HEAD".equals(method)) {
     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
     if (logger.isDebugEnabled()) {
      String requestUri = urlPathHelper.getRequestUri(request);
      logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
     }
     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
      return;
     }
    }
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
     return;
    }
    try {
     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    }
    finally {
     if (asyncManager.isConcurrentHandlingStarted()) {
      return;
     }
    }

    applyDefaultViewName(request, mv);
    mappedHandler.applyPostHandle(processedRequest, response, mv);
   }
   catch (Exception ex) {
    dispatchException = ex;
   }
   processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  }
  catch (Exception ex) {
   triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  }
  catch (Error err) {
   triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
  }
  finally {
   if (asyncManager.isConcurrentHandlingStarted()) {
    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    return;
   }
   if (multipartRequestParsed) {
    cleanupMultipart(processedRequest);
   }
  }
 }
  • 说明
    • 第33行的mappedHandler.applyPreHandle(processedRequest, response)执行的是拦截器中的pre…方法
    • 第37行的mv = ha.handle(processedRequest, response, mappedHandler.getHandler());执行的是控制器中的方法,返回值是一个ModelAndView
    • 第46行的mappedHandler.applyPostHandle(processedRequest, response, mv);执行拦截器中的post…方法
    • 第51行的processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);中的mappedHandler.triggerAfterCompletion(request, response, null);执行affter…方法.
    • 第51行的processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);中的render(mv, request, response);渲染对应视图的

destory方法在Dispatcher中并不重要,因此在此不做分析。

总结

本章节以分析一个Servlet的方式找到了DispatcherServlet的init方法和service方法,简单的描绘了一个servlet的生命周期,在初始化过程中先对各个组件进行初始化,当用户请求过来时,通过service方法处理,分别执行拦截器中的方法和对应控制器中的方法。

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/weixin_39578364/article/details/81569546
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞