springmvc源码(三)

前言

上一篇跟着源码走完了HandlerMapping的创建过程以及对注解的分析和绑定的过程,这一次来看一下HandlerAdapter的过程。

一、initHandlerAdapters

在这里插入图片描述
和initHandlerMapping一样,我们直接进入到getDefaultStrategies当中。

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
        String key = strategyInterface.getName();
        String value = defaultStrategies.getProperty(key);
        if (value == null) {
            return new LinkedList();
        } else {
            String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
            List<T> strategies = new ArrayList(classNames.length);
            String[] var7 = classNames;
            int var8 = classNames.length;

            for(int var9 = 0; var9 < var8; ++var9) {
                String className = var7[var9];

                try {
                    Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                    Object strategy = this.createDefaultStrategy(context, clazz);
                    strategies.add(strategy);
                } catch (ClassNotFoundException var13) {
                    throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var13);
                } catch (LinkageError var14) {
                    throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var14);
                }
            }

            return strategies;
        }
    }

其实这里的创建方式和initHandlerMapping方法是一样的,也是同样的拿到HandlerAdapter的全类名之后,去DispatcherServlet.properties中找到对应的类型然后去实例化。

org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,
org.springframework.web.servlet.function.support.HandlerFunctionAdapter
  • HttpRequestHandlerAdapter是http请求处理器适配器,实现了org.springframework.web.HttpRequestHandler, 接口的Bean通过此适配器进行适配、执行。HttpRequestHandlerAdapter作为HTTP请求处理器适配器仅仅支持对HTTP请求处理器的适配。它简单的将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,它并不需要返回值。它主要应用在基于HTTP的远程调用的实现上。
  • SimpleControllerHandlerAdapter是简单控制器处理器适配器,这个实现类将HTTP请求适配到一个控制器的实现进行处理。这里控制器的实现是一个简单的控制器接口的实现。
  • RequestMappingHandlerAdapter实现了HandlerAdapter接口,顾名思义,表示handler的adapter,这里的handler指的是Spring处理具体请求的某个Controller的方法,也就是说HandlerAdapter指的是将当前请求适配到某个Handler的处理器。RequestMappingHandlerAdapter是HandlerAdapter的一个具体实现,主要用于将某个请求适配给@RequestMapping类型的Handler处理。
  • 至于HandlerFunctionAdapter是有关于函数式接口的。

自然,我们这里使用的就是RequestMappingHandlerAdapter,同样的,他也实现了InitializingBean接口,在创建的时候也会调用afterPropertiesSet方法。

public void afterPropertiesSet() {
        this.initControllerAdviceCache();
        List handlers;
        if (this.argumentResolvers == null) {
            handlers = this.getDefaultArgumentResolvers();
            this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
        }

        if (this.initBinderArgumentResolvers == null) {
            handlers = this.getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
        }

        if (this.returnValueHandlers == null) {
            handlers = this.getDefaultReturnValueHandlers();
            this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
        }
    }

其实就是为SpringMVC接受请求处理的对象准备参数,返回值,初始化绑定参数处理器列表。准备完成之后,HandlerAdapter创建完成,initHandlerAdapters结束。

二、SpringMVC框架对应请求如何处理

继承图
在这里插入图片描述

Servlet实例化,调用init方法和销毁在整个生命周期中只会出现一次,当每次发出请求的时候都会调用service方法【分发请求给对应请求方式对应处理方法】,首先我们找到他的顶级接口GenericServlet,我们很明显的能找到一个service方法。但是这个方法并没有实现,显然是留给子类实现的。
在这里插入图片描述
他有这么两个实现类重写了这个方法,我们需要的显然是HttpServlet。
在这里插入图片描述
将拿到的ServletRequest和ServletResponse转为HttpServletRequest和HttpServletResponse,调用调用本类的service方法。

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

代码比较长,但是并不难理解。首先拿到请求方法的类型,是get还是post等等。我们以get为例。他会直接去调用doGet方法。

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }
    }

这里其实就是判断一下协议类型支不支持,不支持就会报错。并没有做其他操作。那么到底是怎么回事呢,其实这个类也有他的子类重写了这个方法。
在这里插入图片描述
进入到我们继承图中的FrameworkServlet中。

protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.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 = this.buildLocaleContext(request);
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
        this.initContextHolders(request, localeContext, requestAttributes);

        try {
            this.doService(request, response);
        } catch (IOException | ServletException var16) {
            failureCause = var16;
            throw var16;
        } catch (Throwable var17) {
            failureCause = var17;
            throw new NestedServletException("Request processing failed", var17);
        } finally {
            this.resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();
            }

            this.logResult(request, response, (Throwable)failureCause, asyncManager);
            this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
        }

    }

最终进入到processRequest方法。首先获取一下启动时间,然后为了线程安全去拿一个线程副本变量,拿不到在去创建。然后为了将数据存储到request中,去构建一个RequestAttributes,然后将他暴露在我们的上下文对象当中。再去调用doService方法。最后再去清理上下文中的request中的数据。我们来看doService这个方法。

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        this.logRequest(request);
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap();
            Enumeration attrNames = request.getAttributeNames();

            label95:
            while(true) {
                String attrName;
                do {
                    if (!attrNames.hasMoreElements()) {
                        break label95;
                    }

                    attrName = (String)attrNames.nextElement();
                } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

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

        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.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 {
            this.doDispatch(request, response);
        } finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }

此时就已经进入了DispatcherServlet当中。比较重要的其实就是doDispatch这个方法。前面只是给request当中设置一些可用对象而已。然后为了重定向之后能获取到上一个页面,给request当中设置一些属性。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                	//检测是否是文件上传请求
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    //根据当前request对象找到对应处理对象
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
                    //准备参数解析器和返回值解析器
			   		// RequestMappingHandlerAdapter =>判断请求处理方法
                	// Controller  simplecontro1lerHandlerAdapter
			  		// servlet   HttpRequestHandlerAdapter
			  		//HandlerMethod   RequestMappingHandlerAdapter
               		//找到的适配对象就是RequestMappingHandlerAdapter,因为是一个HandlerMethod对象
                    HandlerAdapter ha = this.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 ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
                    //拦截器的PreHandle方法如果返回true,才会继续执行,如果返回false,就返回,不执行请求
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                    
                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
                //处理请求返回的ModelAndView对象【视图渲染工作】
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }
        }
    }

进入这个方法,首先定义了一些变量,然后去检测是不是一个文件上传请求。再然后就是去拿到对应的处理器执行链,在getHandle中。在这里插入图片描述
其实就是去遍历所有的handlerMapping调用getHandler方法去获得执行链。

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = this.getHandlerInternal(request);
        if (handler == null) {
            handler = this.getDefaultHandler();
        }

        if (handler == null) {
            return null;
        } else {
            if (handler instanceof String) {
                String handlerName = (String)handler;
                handler = this.obtainApplicationContext().getBean(handlerName);
            }

            HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Mapped to " + handler);
            } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
                this.logger.debug("Mapped to " + executionChain.getHandler());
            }

            if (this.hasCorsConfigurationSource(handler)) {
                CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
                CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
                config = config != null ? config.combine(handlerConfig) : handlerConfig;
                executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
            }

            return executionChain;
        }
    }

首先,就去调用getHandlerInternal方法去获得处理器,其实就是对应的处理方法。
在这里插入图片描述
可以看到,返回值类型是HandlerMethod类型,我们前面提到过,HandlerMethod这个类其实就对应的是方法。然后再去调用父类的getHandlerInternal方法。

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
      	  //根据请求得到对应的映射路径
          String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
          request.setAttribute(LOOKUP_PATH, lookupPath);
          this.mappingRegistry.acquireReadLock();
          HandlerMethod var4;
          try {
              //通过请求的映射路径找到对应的处理方法及方法上面@RequestMapping注解对应的RequestMappingInfo对象
              HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
              var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
          } finally {
              this.mappingRegistry.releaseReadLock();
          }
  
          return var4;
      }

首先就根据request拿到对应的请求路径,然后把他设置到request中。然后根据这个映射路径去找对应的处理方法,我们前面应该也提到,有两个map集合存储了url,method,和RequestMappingInfo的对应关系。那么我们看看到底是不是这样找到的。进入到lookupHandlerMethod方法。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        if (directPathMatches != null) {
            this.addMatchingMappings(directPathMatches, matches, request);
        }

        if (matches.isEmpty()) {
            this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
        }

        if (!matches.isEmpty()) {
            Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
            matches.sort(comparator);
            AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
            if (matches.size() > 1) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace(matches.size() + " matching mappings: " + matches);
                }

                if (CorsUtils.isPreFlightRequest(request)) {
                    return PREFLIGHT_AMBIGUOUS_MATCH;
                }

                AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.handlerMethod.getMethod();
                    Method m2 = secondBestMatch.handlerMethod.getMethod();
                    String uri = request.getRequestURI();
                    throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
                }
            }

            request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
            this.handleMatch(bestMatch.mapping, lookupPath, request);
            return bestMatch.handlerMethod;
        } else {
            return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }

刚进入这个方法,我们就看到一个Match对象,这个对象是什么呢。在这里插入图片描述
其实这个对象就是将方法和方法上的注解对象进行了一个包装而已。了解了这个之后,我们继续,它会创建一个list集合,用来存储Match对象,接着去url去拿到对应的RequestMappingInfo对象集合。
在这里插入图片描述
这里我们就很清楚了,就是从我们以前的urlLookup中去找,找到对应的RequestMappingInfo。然后返回。找到之后,会把他放到一个个的match中,然后再由matches存储起来。我们来看看是怎么存储的。

private void addMatchingMappings(Collection<T> mappings, List<AbstractHandlerMethodMapping<T>.Match> matches, HttpServletRequest request) {
        Iterator var4 = mappings.iterator();

        while(var4.hasNext()) {
            T mapping = var4.next();
            T match = this.getMatchingMapping(mapping, request);
            if (match != null) {
                matches.add(new AbstractHandlerMethodMapping.Match(match, (HandlerMethod)this.mappingRegistry.getMappings().get(mapping)));
            }
        }
    }

public Map<T, HandlerMethod> getMappings() {
       return this.mappingLookup;
}

依然是去遍历mappings,那么getMatchingMapping这个方法是干什么呢,其实这个方法就是去重新包装RequestMappingInfo,把request中的参数都放到RequestMappingInfo中,有兴趣的可以去看看。包装完成后,就会把这个RequestMappingInfo和他对应的方法包装为一个个match被matches所存起来。那么它对应的方法是怎么来的呢。getMappings这个方法,返回了一个map,可以看到这个map就是当初我们存储RequestMappingInfo和method的map,通过它就可以找到对应的method了。存储好之后,经过一些算法找到比较好的那个处理方法,然后返回。返回到getHandlerInternal当中,拿到对应的HandlerMethod对应的处理方法之后,然后再通过createWithResolvedBean方法给HandlerMethod设置一下他所对应的类之后,将HandlerMethod返回。然后一直返回到getHandler当中。此时我们已经拿到了request对应的处理方法,然后就要去拿到HandlerExecutionChain,也就是处理器链了。

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
        Iterator var5 = this.adaptedInterceptors.iterator();

        while(var5.hasNext()) {
            HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            } else {
                chain.addInterceptor(interceptor);
            }
        }

        return chain;
    }

其实就是把定义的拦截器放到我们执行链中。然后返回,返回到getHandler当中,拿到处理器执行链,然后进行一些跨域的处理之后,返回执行链。返回到doDispatch当中。然后再去拿到处理器设配器。
在这里插入图片描述
依然是遍历查找,选择支持当前类新的Adapter,然后返回到doDispatch当中。拿到之后,请求的处理类型,以get为例,这里有这样一段代码。

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

这里其实就涉及到拦截器的流程,拦截器的实现方法applyPreHandle返回false的时候,那么就不会继续执行,而是返回,只有他返回true的时候才会继续执行处理方法等等。我们主要来看一看他是怎么执行处理方法的。

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return this.handleInternal(request, response, (HandlerMethod)handler);
}

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        this.checkRequest(request);
        ModelAndView mav;
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized(mutex) {
                    mav = this.invokeHandlerMethod(request, response, handlerMethod);
                }
            } else {
                mav = this.invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            mav = this.invokeHandlerMethod(request, response, handlerMethod);
        }

        if (!response.containsHeader("Cache-Control")) {
            if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            } else {
                this.prepareResponse(response);
            }
        }

        return mav;
}

invokeHandlerMethod方法中会去调用invokeAndHandle方法去反射调用处理方法。我们直接看这个方法。

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
        this.setResponseStatus(webRequest);
        if (returnValue == null) {
            if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
                this.disableContentCachingIfNecessary(webRequest);
                mavContainer.setRequestHandled(true);
                return;
            }
        } else if (StringUtils.hasText(this.getResponseStatusReason())) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        Assert.state(this.returnValueHandlers != null, "No return value handlers");

        try {
            this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
        } catch (Exception var6) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
            }

            throw var6;
        }
    }


public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Arguments: " + Arrays.toString(args));
        }

        return this.doInvoke(args);
    }

invokeForRequest方法,也比较容易理解,拿到参数,doInvoke反射调用处理方法。但是getMethodArgumentValues是怎么匹配这些参数的呢。

//参数绑定
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    //得到参数数组
    MethodParameter[] parameters = this.getMethodParameters();
    if (ObjectUtils.isEmpty(parameters)) {
        return EMPTY_ARGS;
    } else {
        Object[] args = new Object[parameters.length];

        for(int i = 0; i < parameters.length; ++i) {
            MethodParameter parameter = parameters[i];
            //得到参数具体的名字
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            //是否提供相应参数的注解,一般是不提供的 为null
            args[i] = findProvidedArgument(parameter, providedArgs);
            if (args[i] == null) {
                //拿到对应的参数解析器
                if (!this.resolvers.supportsParameter(parameter)) {
                    throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
                }

                try {
                    args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                } catch (Exception var10) {
                    if (this.logger.isDebugEnabled()) {
                        String exMsg = var10.getMessage();
                        if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                            this.logger.debug(formatArgumentError(parameter, exMsg));
                        }
                    }

                    throw var10;
                }
            }
        }

        return args;
    }
}

supportsParameter这个方法我们要注意一下。

public boolean supportsParameter(MethodParameter parameter) {
        return this.getArgumentResolver(parameter) != null;
    }


private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        HandlerMethodArgumentResolver result = (HandlerMethodArgumentResolver)this.argumentResolverCache.get(parameter);
        if (result == null) {
            Iterator var3 = this.argumentResolvers.iterator();

            while(var3.hasNext()) {
                HandlerMethodArgumentResolver resolver = (HandlerMethodArgumentResolver)var3.next();
                if (resolver.supportsParameter(parameter)) {
                    result = resolver;
                    this.argumentResolverCache.put(parameter, resolver);
                    break;
                }
            }
        }

        return result;
    }

进入到getArgumentResolver方法,遍历argumentResolvers,因为参数解析器有很多,这里使用的的是RequestParamMethodArgumentResolver类。

public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.hasParameterAnnotation(RequestParam.class)) {
            if (!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
                return true;
            } else {
                RequestParam requestParam = (RequestParam)parameter.getParameterAnnotation(RequestParam.class);
                return requestParam != null && StringUtils.hasText(requestParam.name());
            }
        } else if (parameter.hasParameterAnnotation(RequestPart.class)) {
            return false;
        } else {
            parameter = parameter.nestedIfOptional();
            if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
                return true;
            } else {
                return this.useDefaultResolution ? BeanUtils.isSimpleProperty(parameter.getNestedParameterType()) : false;
            }
        }
    }

进入到这个方法,看看参数是否有RequestParam注解,如果有,在看看RequestParam是不是有参数,有的话返回到getArgumentResolver中,将参数和解析器放到缓存中,便于我们下次使用。最后返回到resolveArgument中。下一步就应该去解析参数了。

public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        AbstractNamedValueMethodArgumentResolver.NamedValueInfo namedValueInfo = this.getNamedValueInfo(parameter);
        MethodParameter nestedParameter = parameter.nestedIfOptional();
        Object resolvedName = this.resolveStringValue(namedValueInfo.name);
        if (resolvedName == null) {
            throw new IllegalArgumentException("Specified name must not resolve to null: [" + namedValueInfo.name + "]");
        } else {
            Object arg = this.resolveName(resolvedName.toString(), nestedParameter, webRequest);
            if (arg == null) {
                if (namedValueInfo.defaultValue != null) {
                    arg = this.resolveStringValue(namedValueInfo.defaultValue);
                } else if (namedValueInfo.required && !nestedParameter.isOptional()) {
                    this.handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
                }

                arg = this.handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
            } else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
                arg = this.resolveStringValue(namedValueInfo.defaultValue);
            }

            if (binderFactory != null) {
                WebDataBinder binder = binderFactory.createBinder(webRequest, (Object)null, namedValueInfo.name);

                try {
                    arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
                } catch (ConversionNotSupportedException var11) {
                    throw new MethodArgumentConversionNotSupportedException(arg, var11.getRequiredType(), namedValueInfo.name, parameter, var11.getCause());
                } catch (TypeMismatchException var12) {
                    throw new MethodArgumentTypeMismatchException(arg, var12.getRequiredType(), namedValueInfo.name, parameter, var12.getCause());
                }
            }

            this.handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
            return arg;
        }
    }

首先就是去拿到参数名字,拿到名字之后,resolveName去解析。

protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
        HttpServletRequest servletRequest = (HttpServletRequest)request.getNativeRequest(HttpServletRequest.class);
        Object arg;
        if (servletRequest != null) {
            arg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
            if (arg != MultipartResolutionDelegate.UNRESOLVABLE) {
                return arg;
            }
        }
        arg = null;
        MultipartRequest multipartRequest = (MultipartRequest)request.getNativeRequest(MultipartRequest.class);
        if (multipartRequest != null) {
            List<MultipartFile> files = multipartRequest.getFiles(name);
            if (!files.isEmpty()) {
                arg = files.size() == 1 ? files.get(0) : files;
            }
        }

        if (arg == null) {
            String[] paramValues = request.getParameterValues(name);
            if (paramValues != null) {
                arg = paramValues.length == 1 ? paramValues[0] : paramValues;
            }
        }

        return arg;
    }

我们这里不是上传请求,所以直接到getParameterValues方法。

public String[] getParameterValues(String paramName) {
        return this.getRequest().getParameterValues(paramName);
    }

这里比较熟悉了,request.getParameterValues()方法获取参数值。我们拿到了参数名字,自然能获取到参数值。获取到之后,判断是不是只有一个值,如果是返回数组第一个位置,否则直接返回数组。返回到resolveArgument当中。经过这样的处理,我们就匹配到了参数,得到了参数数组,返回到invokeForRequest方法中,最后doInvoke反射执行处理方法。到这其实大体流程就结束了。

结束

其中有不对的地方,还请指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值