SpringMVC源码分析(3)DispatcherServlet的请求处理流程

本文详细剖析了SpringMVC的请求处理流程,包括DispatcherServlet如何解析请求、定位控制器方法、执行拦截器以及渲染视图等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<SpringMVC源码分析(1)标签解析>:介绍了解析过程中,初始化若干组件。

<SpringMVC源码分析(2)DispatcherServlet的初始化>:初始化DispatcherServlet的多个组件。

本文继续分析DispatcherServlet解析请求的过程。

概览


  ①:DispatcherServlet是springmvc中的前端控制器(front controller),负责接收request并将request转发给对应的处理组件.

  ②:HanlerMapping是springmvc中完成url到controller映射的组件.DispatcherServlet接收request,然后从HandlerMapping查找处理request的controller.

  ③:Cntroller处理request,并返回ModelAndView对象,Controller是springmvc中负责处理request的组件(类似于struts2中的Action),ModelAndView是封装结果视图的组件.

  ④ ⑤ ⑥:视图解析器解析ModelAndView对象并返回对应的视图给客户端.

要点

  1. 维护url和controller的映射

    这部分工作由的父类

    实现。具体方法为detectHandlers

protected void detectHandlers() throws BeansException {
   if (()) {
      ("Looking for URL mappings in application context: " + getApplicationContext());
   }
   String[] beanNames = ( ?
         (getApplicationContext(), ) :
         getApplicationContext().getBeanNamesForType());

   // Take any bean name that we can determine URLs for.
   for (String beanName : beanNames) {
      String[] urls = determineUrlsForHandler(beanName);
      if (!(urls)) {
         // URL paths found: Let's consider it a handler.
         registerHandler(urls, beanName);
      }
      else {
         if (()) {
            ("Rejected bean name '" + beanName + "': no URL paths identified");
         }
      }
   }
}

2.准确定位处理请求的具体方法(在AnnotationMethodHandlerAdapter中实现)

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {

   ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
   Method handlerMethod = (request);//具体实现方法的匹配
   ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   ExtendedModelMap implicitModel = new BindingAwareModelMap();

   Object result = (handlerMethod, handler, webRequest, implicitModel);
   ModelAndView mav =
         (handlerMethod, (), result, implicitModel, webRequest);
   (handler, (mav != null ? () : null), implicitModel, webRequest);
   return mav;
}





1.请求入口

@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   processRequest(request, response);
}

/**
 * Delegate POST requests to {@link #processRequest}.
 * @see #doService
 */
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   processRequest(request, response);
}

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

   long startTime = ();
   Throwable failureCause = null;

   // Expose current LocaleResolver and request as LocaleContext.
   LocaleContext previousLocaleContext = ();
   (buildLocaleContext(request), );
   // Expose current RequestAttributes to current thread.
   RequestAttributes previousRequestAttributes = ();
   ServletRequestAttributes requestAttributes = null;
   if (previousRequestAttributes == null || ().equals()) {
      requestAttributes = new ServletRequestAttributes(request);
      (requestAttributes, );
   }

   if (()) {
      ("Bound request context to thread: " + request);
   }

   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 {
      // Clear request attributes and reset thread-bound context.
      (previousLocaleContext, );
      if (requestAttributes != null) {
         (previousRequestAttributes, );
         ();
      }
      if (()) {
         ("Cleared thread-bound request context: " + request);
      }

      if (failureCause != null) {
         ("Could not complete request", failureCause);
      }
      else {
         ("Successfully completed request");
      }
      if () {
         // Whether or not we succeeded, publish an event.
         long processingTime = () - startTime;
         (
               new ServletRequestHandledEvent(this,
                     (), (),
                     (), getServletConfig().getServletName(),
                     (request), getUsernameForRequest(request),
                     processingTime, failureCause));
      }
   }
}

processRequest方法主要做4项工作。

  1. 得到当前线程的LocaleContext和RequestAttributes,创建新的LocaleContext和RequestAttributes并重新绑定到当前线程。

  2. 调用子类实现的doService()

  3. 重置当前线程的LocaleContext和RequestAttributes

  4. 执行成功后,发布ServletRequestHandledEvent事件。

自定义的doService方法

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (()) {
      String requestUri = (request);
      ("DispatcherServlet with name '" + getServletName() + "' processing " + () +
            " 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 ((request)) {
      ("Taking snapshot of request attributes before include");
      attributesSnapshot = new HashMap<String, Object>();
      Enumeration attrNames = ();
      while (()) {
         String attrName = (String) ();
         if ( || ("")) {
            (attrName, (attrName));
         }
      }
   }

   // Make framework objects available to handlers and view objects.
   (WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
   (LOCALE_RESOLVER_ATTRIBUTE, );
   (THEME_RESOLVER_ATTRIBUTE, );
   (THEME_SOURCE_ATTRIBUTE, getThemeSource());

   try {
      doDispatch(request, response);
   }
   finally {
      // Restore the original attribute snapshot, in case of an include.
      if (attributesSnapshot != null) {
         restoreAttributesAfterInclude(request, attributesSnapshot);
      }
   }
}

主要做两部分工作

  1. 如果是include请求,先保存一份request域数据的快照,doDispatch执行过后,将会用快照数据恢复。

  2. 调用doDispatch方法,完成请求转发。

方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;
   int interceptorIndex = -1;

   try {
      ModelAndView mv;
      boolean errorView = false;

      try {
      // 1.检查是否是文件上传的请求
         processedRequest = checkMultipart(request);

         // Determine handler for the current request.
          // 2.取得处理当前请求的controller,这里也称为hanlder,处理器,第一个步骤的意义就在这里体现了.
          //这里并不是直接返回controller,而是返回的HandlerExecutionChain请求处理器链对象,该对象封装了handler和interceptors.
         mappedHandler = getHandler(processedRequest, false);
         if (mappedHandler == null || () == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
         //3. 获取处理request的处理器适配器handler adapter 
         HandlerAdapter ha = getHandlerAdapter(());

               // Process last-modified header, if supported by the handler.
         String method = ();
         boolean isGet = "GET".equals(method);
         if (isGet || "HEAD".equals(method)) {
            long lastModified = (request, ());
            if (()) {
               String requestUri = (request);
               ("Last-Modified value for [" + requestUri + "] is: " + lastModified);
            }
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }

         // Apply preHandle methods of registered interceptors.
          // 4.拦截器的预处理方法
         HandlerInterceptor[] interceptors = ();
         if (interceptors != null) {
            for (int i = 0; i < ; i++) {
               HandlerInterceptor interceptor = interceptors[i];
               if (!(processedRequest, response, ())) {
                  triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
                  return;
               }
               interceptorIndex = i;
            }
         }

         // Actually invoke the handler.
         // 5.实际的处理器处理请求,返回结果视图对象
         mv = (processedRequest, response, ());

         // Do we need view name translation?
         if (mv != null && !()) {
            (getDefaultViewName(request));
         }

         // Apply postHandle methods of registered interceptors.
         // 6.拦截器的后处理方法
         if (interceptors != null) {
            for (int i =  - 1; i >= 0; i--) {
               HandlerInterceptor interceptor = interceptors[i];
               (processedRequest, response, (), mv);
            }
         }
      }
      catch (ModelAndViewDefiningException ex) {
         ("ModelAndViewDefiningException encountered", ex);
         mv = ();
      }
      catch (Exception ex) {
         Object handler = (mappedHandler != null ? () : null);
         mv = processHandlerException(processedRequest, response, handler, ex);
         errorView = (mv != null);
      }

      // Did the handler return a view to render?
      if (mv != null && !()) {
         render(mv, processedRequest, response);
         if (errorView) {
            (request);
         }
      }
      else {
         if (()) {
            ("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                  "': assuming HandlerAdapter completed request handling");
         }
      }

      // Trigger after-completion for successful outcome.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
   }

   catch (Exception ex) {
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
   }
   catch (Error err) {
      ServletException ex = new NestedServletException("Handler processing failed", err);
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
   }

   finally {
      // Clean up any resources used by a multipart request.
      if (processedRequest != request) {
         cleanupMultipart(processedRequest);
      }
   }
}

很明显这儿是SpringMVC核心。

1.根据请求的路径找到HandlerMethod(带有Method反射属性,也就是对应Controller中的方法)(完成)

2.匹配路径对应的拦截器(完成)

3.获得HandlerExecutionChain对象(完成)

4.通过HandlerAdapter对象进行处理得到ModelAndView对象(HandlerAdapter.handle)

5.调用

6.调用HandlerInterceptor.postHandle

7. 渲染


4.总结


简单粗暴的总结下

step1-6: 获取controller

step5-15 :调用controller方法

step17-20:渲染view

其他:aop方式处理拦截统一处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值