spring

Spring Mvc源码分析

2021-10-03  本文已影响0人  念䋛

Spring Mvc源码分析

  1. mvc源码图解
    springmvc经过一系列的调用到DispatcherServlet类的doService方法,调用doDispatch方法
    doDispatch方法的重要代码
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,得到过滤器链和handler(里面就包含了 真正要调用的方法)
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
//通过handler获取HandlerAdapter,这里是注解,所以我们获取到的是//HttpRequestHandlerAdapter,下面就用得到的HttpRequestHandlerAdapter处理拦截器
//和实际方法的调用
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

         // Process last-modified header, if supported by the handler.
         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;
            }
         }
//调用拦截器的preHandler,如果返回false,则调用结束
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.
//处理实际方法
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }

         applyDefaultViewName(processedRequest, mv);
//调用拦截器的postHandler方法
         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);
      }
//处理异常,如果我们配置了统一异常,就在这里执行,并会执行拦截器的afterCompletion方法
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
//执行拦截器的afterCompletion方法
      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
   }
   catch (Throwable err) {
//执行拦截器的afterCompletion方法,到这就会发现afterCompletion方法总是会执行
//所以afterCompletion方法中可以关闭流或者链接
      triggerAfterCompletion(processedRequest, response, mappedHandler,
            new NestedServletException("Handler processing failed", err));
   }
   finally {
      if (asyncManager.isConcurrentHandlingStarted()) {
         // Instead of postHandle and afterCompletion
         if (mappedHandler != null) {
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
         }
      }
      else {
         // Clean up any resources used by a multipart request.
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

getHandler方法,得到HandlerExecutionChain,前提是url匹配到了路径,就是@Controller中的@RequestMapping被匹配到,如果匹配不到handler为null


image.png

getHandlerAdapter方法,获取处理getHandler返回的HandlerExecutionChain,我们得到的是
HttpRequestHandlerAdapter


image.png

applyPreHandler方法,调用实际方法之前先调用拦截器的preHandler方法


image.png

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
通过debug方式最终调用到RequestMappingHandlerAdapter#handleInternal方法


@Override
protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ModelAndView mav;
   checkRequest(request);

   // Execute invokeHandlerMethod in synchronized block if required.
//因为session是线程不安全,这里处理多个线程同时访问的安全问题
//默认为false
   if (this.synchronizeOnSession) {
//获取session,如果没有不创建session
      HttpSession session = request.getSession(false);
      if (session != null) {
         Object mutex = WebUtils.getSessionMutex(session);
//多个线程,同时只处理一个,保证线程安全
         synchronized (mutex) {
            mav = invokeHandlerMethod(request, response, handlerMethod);
         }
      }
      else {
//如果没有session
         // No HttpSession available -> no mutex necessary
         mav = invokeHandlerMethod(request, response, handlerMethod);
      }
   }
   else {
      // No synchronization on session demanded at all...
// invokeHandlerMethod方法调用我们实际的要调用的方法
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }

   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
      if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
         applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
      }
      else {
         prepareResponse(response);
      }
   }
   return mav;
}

invokeHandlerMethod
--invocableMethod.invokeAndHandle(webRequest, mavContainer);代码
--> invokeAndHandle 方法中的 returnValue = invokeForRequest(webRequest,
mavContainer,providedArgs);代码
,其余的我也没自己看过那我们就看一看invokeForRequest方法

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//解析实际调用方法上的变量赋值,像我们比较常用的GET请求路径赋值变量@PathVariable //POST请求的@RequestBody 还有继承HandlerMethodArgumentResolver接口, //supportsParameter方法判断方法的入参是否是某个类,如果是返回true在resolveArgument方法
//将类赋值,经常的用法是权限登入,在系统中保存当前登入人的信息,User类,在方法中入参包含//User类,就会自动的赋值上,当然继承HandlerMethodArgumentResolver类要放到//HandlerMethodArgumentResolver中,会在下面用图片展示一下
    Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
//真正调用方法
    return this.doInvoke(args);
}

如何用HandlerMethodArgumentResolver将变量赋值到方法的入参里


image.png
image.png
image.png
image.png
image.png
image.png
上一篇 下一篇

猜你喜欢

热点阅读