美文网首页spring
Spring Mvc源码分析

Spring Mvc源码分析

作者: 念䋛 | 来源:发表于2021-10-03 21:46 被阅读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

    相关文章

      网友评论

        本文标题:Spring Mvc源码分析

        本文链接:https://www.haomeiwen.com/subject/vypbnltx.html