《SpringMVC系列》第二章:HandlerAdapter处理适配器

一、写在前面

1.概述

之前我们讲到了通过请求找到了对应的映射器,也就是找到了对应的方法,那么如何调用这个方法呢,因为不同的接收请求方法有不同的方式,最简单的就是方法名就不一样,那么如何调用,这里采用了设计模式中的适配器模式,通过适配,进行判断,然后通过不同的方式调用方法,这就是HandlerAdpater 的主要功能

2.请求流程

之前介绍了HandlerMapping,我们通过请求找到了对应的handler,那么我们继续来看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.
                 // 将我们的请求和逻辑方法映射起来
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
                      // 如果没有找到映射器 代表没有找到接口方法 设置返回404
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
                 // 通过映射器,找到对应的设配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				
                 // 执行拦截器的前置方法 按照顺序执行
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
                 // 通过适配器调用接口方法 
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
                 // 执行拦截器的后置方法 按照配置的倒序执行 
				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);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			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);
				}
			}
		}
	}

我们先看没有找到对应的Handler的对象,如果没有找到Handler对象的话,就执行noHandlerFound(processedRequest, response);的方法,具体的代码如下:

	protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
         // 日志打印
		if (pageNotFoundLogger.isWarnEnabled()) {
			pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
		}
         // 是否出现了异常
		if (this.throwExceptionIfNoHandlerFound) {
			throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
					new ServletServerHttpRequest(request).getHeaders());
		}
		else {
             // 没有出现异常 直接返回404
			response.sendError(HttpServletResponse.SC_NOT_FOUND);
		}
	}

上面的代码其实很简单,判断是否需要打印日志,如果需要,就直接打印日志,如果在查找Handler的时候出错了,就直接抛出异常,如果没有出现异常,就直接将状态码设置成404,然后返回。

然后就是根据对应的Handler获取对应的HandlerAdapter。这个时候会调用getHandlerAdapter(mappedHandler.getHandler());方法,具体的代码如下:

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

上面运行到了 HandlerAdapter,下面会先介绍一下HandlerAdapter 这个接口和其常用子类

二、HandlerAdapter

1.HandlerAdapter接口

该接口中有3个方法

public interface HandlerAdapter {
	// 判断该适配器是否支持传入的handler
	boolean supports(Object handler);
	// 使用给定的handler来处理当前的request请求,调用对应的逻辑方法
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	// 返回handler最后修改的时间 该方法已经标记为废弃
	@Deprecated
	long getLastModified(HttpServletRequest request, Object handler);
}

2.常见子类

HandlerAdapter 系统出提供了一些子类,但是我们也可以对其进行扩展,例如Spring Boot就对其就行了扩展

HttpRequestHandlerAdapter

SimpleControllerHandlerAdapter

RequestMappingHandlerAdapter

RequestMappingHandlerAdapter

3.初始化

HandlerAdapter 和 之前介绍的 HandlerMapping 初始化思路是一样,调用链:

org.springframework.web.servlet.HttpServletBean#init()
--> org.springframework.web.servlet.FrameworkServlet#initServletBean()
--> org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext()
--> org.springframework.web.servlet.DispatcherServlet#onRefresh()
--> org.springframework.web.servlet.DispatcherServlet#initStrategies()
--> org.springframework.web.servlet.DispatcherServlet#initHandlerAdapters()

通过上面的调用链,我们会调用初始化处理适配器方法 initHandlerAdapters

	private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;

		if (this.detectAllHandlerAdapters) {
			// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
             // 从spring的容器中取,如果这儿加了@EnableWebMvc注解,这儿取出来的就是三个
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<>(matchingBeans.values());
				// We keep HandlerAdapters in sorted order.
                // 如果不为空,我们进行处理排序,因为适配器有匹配顺序
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerAdapter later.
			}
		}

		// Ensure we have at least some HandlerAdapters, by registering
		// default HandlerAdapters if no other adapters are found.
         // 如果上面没有从Spring中获取不到适配器,那么就从配置文件中去默认的
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

上面的代码就是如果加了@EnableWebMvc注解的话,就直接能从spring容器中取出对应的三个HandlerMapping,如果没有加,则调用 getDefaultStrategies() 方法,

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		if (defaultStrategies == null) {
			try {
				// Load default strategy implementations from properties file.
				// This is currently strictly internal and not meant to be customized
				// by application developers.
                  // 从默认的配置中 ‘DispatcherServlet.properties’ 取值 
				ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
                  // 加载属性
				defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
			}
			catch (IOException ex) {
				throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
			}
		}
         // 遍历默认的映射器注入
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherServlet's default strategy class [" + className +
							"] for interface [" + key + "]", ex);
				}
				catch (LinkageError err) {
					throw new BeanInitializationException(
							"Unresolvable class definition for DispatcherServlet's default strategy class [" +
							className + "] for interface [" + key + "]", err);
				}
			}
			return strategies;
		}
		else {
			return Collections.emptyList();
		}
	}

上面的代码说如果spring容器中取不到,那么会从默认的配置文件中取,这个配置在通过IDEA中查看jar包 spring-webmvc-5.3.9.jar,打开可以看到其中的一段配置

org.springframework.web.servlet.HandlerAdapter=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

三、适配调用

上面我们通过doDispatch()方法调用到了 HandlerAdapter,上面我们介绍了这个接口及其子类,那么接下来我们按照类图来介绍一下接口

1.HttpRequestHandlerAdapter

我们先看一下这个类的结构,看看有没有利用spring的一些扩展点,来完成一些数据的初始化的工作,具体如下:

《SpringMVC系列》第二章:HandlerAdapter处理适配器_第1张图片
可以发现这个类没有实现spring的扩展点,就是实现了HandlerAdapter这个接口

public class HttpRequestHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
         // 判断这个handler是否实现了HttpRequestHandler接口
		return (handler instanceof HttpRequestHandler);
	}

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 这里只是把handler强转一下,然后调用对应的handleRequest()方法
		((HttpRequestHandler) handler).handleRequest(request, response);
		return null;
	}
	// getLastModified() 方法已经标记废弃,这里省略
}

我们可以从上面的内容中看到,这个类很简单,调用supports方法来进行适配,这个方法也只是进行了强转判断,并且在适配调用逻辑方法的适合,也很好理解,

测试代码

@Component("/name")
public class BeanNameController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("实现Controller接口方式");
        return null;
    }
}

getHandlerAdapter()这个方法里面,会遍历 handlerAdapter集合,来查找这个handlerAdapter是否匹配这个Handler,找到1个就直接返回,所以这个匹配是存在顺序的,第一步就是BeanNameUrlHandlerMapping,也就是Bean的name是以“/”开头的都是会匹配到,并且这个类是实现了HttpRequestHandler接口的类,才会返回这种适配器,返回这个适配器以后,继续往下执行代码,首先会先执行拦截器的前置方法preHandle()方法,然后就会通过适配器调用到handle()方法,这个从类中就可以看到强转一下直接调用,很简单。

2.SimpleControllerHandlerAdapter

有了上面的介绍,我们看这个就很好理解了,和上面的类似
《SpringMVC系列》第二章:HandlerAdapter处理适配器_第2张图片
对应的类内容:

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
         // 强转判断
		return (handler instanceof Controller);
	}

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 强转调用方法
		return ((Controller) handler).handleRequest(request, response);
	}

	// getLastModified() 方法已经标记废弃,这里省略
}

测试代码

@Component("/name")
public class BeanNameController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("实现Controller接口方式");
        return null;
    }
}

3.HandlerFunctionAdapter

类图
《SpringMVC系列》第二章:HandlerAdapter处理适配器_第3张图片
可以发现这个类实现Ordered接口,没有实现其他的特殊的接口,可以得出没有利用Spring的扩展点,接下来我们就看这个类的supports的方法,具体的代码如下:

@Override
public boolean supports(Object handler) {
	return handler instanceof HandlerFunction;
}

只要handler的类型是HandlerFunction就返回true,所以在什么时候会返回true呢?由上一篇博客,我们可以得出,如果查找出来的Handler是RouterFunctionMapping,这个方法就会返回true

4.RequestMappingHandlerAdapter(重点)

类介绍

这个类主要用来适配添加了@Controller@RequestMapping注解的类,首先看一下这个类图
《SpringMVC系列》第二章:HandlerAdapter处理适配器_第4张图片
这儿实现了ApplicationContextAwareBeanFactoryAwareInitializingBean接口,这3个接口实现的方法都会在容器启动时运行的,其中ApplicationContextAware中的接口的方法不用看的,因为是父类实现了而且也没有调用这个类中的方法,接下来看下BeanFactoryAware接口中的setBeanFactory的方法,具体的代码如下:

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		if (beanFactory instanceof ConfigurableBeanFactory) {
			this.beanFactory = (ConfigurableBeanFactory) beanFactory;
		}
	}

可以发现这个类就是Spring的bean的工厂设置给属性beanFactory,接下来我们继续看实现InitializingBean中的afterPropertiesSet方法,具体的代码如下:

public void afterPropertiesSet() {
		// Do this first, it may add ResponseBody advice beans
  		//初始化 @ControllerAdvice 注解需要的东西,后面写篇博客介绍下这个注解
		initControllerAdviceCache();

  		//获取调用的方法的参数
		if (this.argumentResolvers == null) {
        	//Spring提供的一系列的HandlerMethodArgumentResolver,同时这儿也会调用用户自己添加的HandlerMethodArgumentResolver
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
  		//获取桥接方法的参数
		if (this.initBinderArgumentResolvers == null) {
      		//Spring提供的一系列的HandlerMethodArgumentResolver,同时这儿也会调用用户自己添加的HandlerMethodArgumentResolver
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
  		//获取方法的返回的参数
		if (this.returnValueHandlers == null) {
      		//Spring提供的一系列的HandlerMethodReturnValueHandler,同时这儿也会调用用户自己添加的HandlerMethodReturnValueHandler
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}

上面就是完成了一系列的初始化的工作,同时添加了方法参数的解析器,以及一些处理方法返回值的处理器。这些在调用调用指定的方法和处理返回值的时候有用

Supports()

看完了上面的那些扩展点,我们需要看下这个类中的supports的方法,具体的代码如下

public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

RequestMappingHandlerAdapter类的supportsInternal()

	@Override
	protected boolean supportsInternal(HandlerMethod handlerMethod) {
		return true;
	}

判断类型是否是HandlerMethod,而第二个方法默认是返回true,所以这种的匹配的规则就是,加了@RequestMapping或者@Controller的类,同时这个类中的所有加@RequestMapping的方法都是会被解析成HandlerMethod类型的handler

handle()

引入

上面介绍了适配方法Supports(),接下来详细介绍一下RequestMappingHandlerAdapter适配器的handle()方法,这个方法跟其它适配类中的相同,都是调用对应的接口方法,但是这里需要考虑2点,

  1. 方法是如何被调用的?

  2. 方法的参数是如何传递过去的?

从Java语言的角度来考虑方法如何被调用,通常我们在一个类调用另外一个类的方法,可以想到有那么几种方式,

(1)最常见的就是创建这个类的对象,然后直接调用方法,但是必须知道方法名,但是这里调用,我们并不知道方法名

(2)通过Servlet来请求转发调用另外体一个Servlet的方法,但是这里我们被调用的方法只是一个普通的类

(3) 通过一个接口,对外开放一个方法,类似与上面的HttpServerServlet和Controller接口,但是这样的话,一个类只能写一个方法,不太合适,

(4) 通过反射反射来调用方法,该种适配器就是采用的反射来调用接口方法

初始调用链

接下来我们来看对应的方法,首先调用到AbstractHandlerMethodAdapter类的handle()

	@Override
	@Nullable
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}

调用handleInternal(request, response, (HandlerMethod) handler)方法

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

		ModelAndView mav;
        // 检查请求的会话是否支持
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
        // 默认的情况下这个值是false,所以会执行else中的代码
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
            // 调用对应的方法
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

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

		return mav;
	}

继续调用URL映射的方法 invokeHandlerMethod(request, response, handlerMethod)

	@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		// 将request和response包装成ServletWebRequest对象
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
            //返回Web数据绑定器工厂
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            //返回模型工厂
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
            
            // 返回要调用的方法
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            // 设置参数的解析器
			if (this.argumentResolvers != null) {
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
            // 设置方法的返回类型参数
			if (this.returnValueHandlers != null) {
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
            // 设置方法的返回类型参数
			invocableMethod.setDataBinderFactory(binderFactory);
            // 设置对应的方法参数名发现器,就是用来查找方法的参数名称的,因为JDK自带的只会返回arg0
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
			
            // 创建模型和试图的容器
			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            // 设置只读的Input属性
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            // 初始化模型
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            // 设置忽略重定向默认模型
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
 			
            // 创建异步的请求
			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            // 设置对应的超时时间
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);
            
            // 异步请求的管理器
			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			// 设置任务
            asyncManager.setTaskExecutor(this.taskExecutor);
            // 设置异步的请求
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			// 注册一下拦截器
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

			if (asyncManager.hasConcurrentResult()) {
				Object result = asyncManager.getConcurrentResult();
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
				asyncManager.clearConcurrentResult();
				LogFormatUtils.traceDebug(logger, traceOn -> {
					String formatted = LogFormatUtils.formatValue(result, !traceOn);
					return "Resume with async result [" + formatted + "]";
				});
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}
			
            // 真正的调用处理
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}
			
            // 获取对应的modelAndView对象
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

上面就进行一系列的参数的赋值,最后真正调用方法的 invokeAndHandle(webRequest, mavContainer)

	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		
        // 通过反射调用该请求的方法
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
				disableContentCachingIfNecessary(webRequest);
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}

		mavContainer.setRequestHandled(false);
		Assert.state(this.returnValueHandlers != null, "No return value handlers");
		try {
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(formatErrorForReturnValue(returnValue), ex);
			}
			throw ex;
		}
	}

继续调用 invokeForRequest(webRequest, mavContainer, providedArgs)

	@Nullable
	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 获取该方法的实参
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
        // 通过反射调用该方法
		return doInvoke(args);
	}

上面的代码包括两步,第1 通过 getMethodArgumentValues()方法来获取参数,第2 通过doInvoke()来执行对应的方法,是通过反射来执行,然后将结果返回,

那么首先来看获取实参的处理,整体的一个思路就是 首先获取到该方法的全部形参,然后通过参数解析器,现在请求里面通过类型找,然后在通过形参名找,如此把请求携带的参数自动赋值到实参里面

	protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 获取方法的参数, 注意看这里是直接调用方法,前面没有类名,
         // 本方法处于InvocableHandlerMethod类,是HandlerMethod的子类
         // 我们前面获取的映射器是InvocableHandlerMethod的子类,所以直接调用
         // 所以获取到的就是该方法的形参列表数组
         // 点进到 getMethodParameters()方法里面 就是HandlerMethod类的getter方法
         // 下面看到了其关系图
		MethodParameter[] parameters = getMethodParameters();
        // 如果参数为空,代表该方法不需要形参,直接返回结合
		if (ObjectUtils.isEmpty(parameters)) {
			return EMPTY_ARGS;
		}
  		// 创建参对象 存储方法实参
		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) {
				continue;
			}
            // 查找对应的参数的处理器,主要是遍历所有的参数的处理器,调用处理中的support方法,只要满足就返回true
            // 不同的参数类型有不同的处理器
            // 参数类型的初始化在后面介绍
			if (!this.resolvers.supportsParameter(parameter)) {
                 // 如果没有找到参数解析器 就报异常
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
                // 找到了就直接执行参数处理器的resolveArgument() 解析参数 获取实参
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			}
			catch (Exception ex) {
				// Leave stack trace for later, exception may actually be resolved and handled...
				if (logger.isDebugEnabled()) {
					String exMsg = ex.getMessage();
					if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
						logger.debug(formatArgumentError(parameter, exMsg));
					}
				}
				throw ex;
			}
		}
		return args;
	}

《SpringMVC系列》第二章:HandlerAdapter处理适配器_第5张图片

上面看到我们首先会查询该形参是否存在匹配的参数解析器,如果不存在就报异常,看一下supportsParameter(parameter)方法

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return getArgumentResolver(parameter) != null;
	}

继续调用 getArgumentResolver()

	@Nullable
	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        // 先尝试从缓存中获取 这个是存在缓存的
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
             // 遍历所有的参数处理器,调用每一个参数处理器的 supportsParameter 方法,直到返回的结果为true为止
             // 下面介绍该参数解析器在哪里初始化的
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
                  // 依次判断
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
                      // 如果匹配到 就存入缓存
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

上面我们介绍了如何匹配参数解析器,接下来我们看一下resolveArgument()

当我们,其实注意看一下类结构,这前后用的几个方法 supportsParameter()resolveArgument()getArgumentResolver()都是HandlerMethodArgumentResolverComposite 类的,而且并排的三个方法

   @Override
   @Nullable
   public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
   		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
   	// 继续调用 getArgumentResolver() 方法获取到对应的参数解析器
   	HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
        // 如果为空 直接报异常 代表没有解析器可以解析该参数
   	if (resolver == null) {
   		throw new IllegalArgumentException("Unsupported parameter type [" +
   				parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
   	}
        // 上面获取到了解析器,接下来解析参数 因为不同的参数解析器,解析方法不同
   	return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
   }

我们方法的形参有不同的类型,有包装类,字符串,基本数据类型,数组、引用数据类型等等,那么会分成2种情况,第一种就是普通的类型,第二种就是引用对象,SpringMVC会自动把参数封装到对象里面

普通形参匹配

普通的参数,一般会跳转到 AbstractNamedValueMethodArgumentResolver 类,然后我们查看其中的resolveArgument(),具体的代码如下:

public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

    // 获取方法的形参名信息 NamedValueInfo是一个静态内部类 包含这个形参的名称、required、defaultValue信息
    // 如果形参有@RequestParam注解 则注解信息都会保存在NamedValueInfo这里
	NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
    // 获取包装的方法参数的类型
	MethodParameter nestedParameter = parameter.nestedIfOptional();

    // 从上面的namedValueInfo单独取出形参名
	Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
    // 非空判断
	if (resolvedName == null) {
		throw new IllegalArgumentException(
				"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
	}

    // 获取参数的值
	Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
    // 获取的值为空
	if (arg == null) {
         // 查看是否有默认值,设置默认值
		if (namedValueInfo.defaultValue != null) {
			arg = resolveStringValue(namedValueInfo.defaultValue);
		}
		else if (namedValueInfo.required && !nestedParameter.isOptional()) {
            // 判断是否是必须要值,如果是直接抛出异常
			handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
		}
        // 处理空值,如果这个值的类型是Boolean类型,就设置为false,其他的情况下都是原来的默认值
		arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
	}
	else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
         // 获取值为""同时默认值也不为空,那么就将默认值设置进去
		arg = resolveStringValue(namedValueInfo.defaultValue);
	}

    // 进行类型转换 因为URL请求接收的一般都是String类型,而我们的形参存在各种类型
	if (binderFactory != null) {
		WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
		try {
             // 在这里进行类型转换 转换成正确的参数类型
			arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
		}
		catch (ConversionNotSupportedException ex) {// 类型转换异常
			throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
					namedValueInfo.name, parameter, ex.getCause());
		}
		catch (TypeMismatchException ex) {// 类型找不到异常
			throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
					namedValueInfo.name, parameter, ex.getCause());
		}
         // 最极端情况 值为空&&默认值为空&&必填 报异常
         if (arg == null && namedValueInfo.defaultValue == null &&
					namedValueInfo.required && !nestedParameter.isOptional()) {
			handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);
		}
	}

	handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
	
    //返回处理好的参数的
	return arg;
}

由于RequestParamMethodArgumentResolver类没有实现HandlerMethodArgumentResolver接口,所以这儿调用的是父类的resolveArgument方法,但是获取对应参数的值是调用子类RequestParamMethodArgumentResolverresolveName方法,具体的代码如下:

protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
    // 获取请求
	HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
	if (servletRequest != null) {
		Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
		if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
			return mpArg;
		}
	}

	Object arg = null;
    // 处理文件的
	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) {
        // 重点在这里 还是调用请求的API来获取参数 返回是个数组
		String[] paramValues = request.getParameterValues(name);
		if (paramValues != null) {
			arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
		}
	}
	return arg;
}

我们终于看到对应参数的获取方法resolveName(),就是利用了servlet的api来获取指定的参数的值的。我们继续看上面的resolveArgument()剩余的代码,注释内容都在上面写清楚了,这里就不在重复了。

引用类型形参匹配

当我们的形参有引用类型,SpringMVC会把参数自动封装到对象,其中SpringMVC会首先创建这个对象,然后拿其中的字段去匹配,这个时候我们使用的适配器为

ModelAttributeMethodProcessorresolveArgument()

	@Override
	@Nullable
	public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
		Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
		// 获取到引用类型形参名
		String name = ModelFactory.getNameForParameter(parameter);
		ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
		if (ann != null) {
			mavContainer.setBinding(name, ann.binding());
		}

		Object attribute = null;
		BindingResult bindingResult = null;

		if (mavContainer.containsAttribute(name)) {
			attribute = mavContainer.getModel().get(name);
		}
		else {
			// Create attribute instance
			try {
                  // 创建对象示例 即使没有匹配到任何参数,但是对象肯定有 只是字段值都为空
				attribute = createAttribute(name, parameter, binderFactory, webRequest);
			}
			catch (BindException ex) {
				if (isBindExceptionRequired(parameter)) {
					// No BindingResult parameter -> fail with BindException
					throw ex;
				}
				// Otherwise, expose null/empty value and associated BindingResult
				if (parameter.getParameterType() == Optional.class) {
					attribute = Optional.empty();
				}
				else {
					attribute = ex.getTarget();
				}
				bindingResult = ex.getBindingResult();
			}
		}

		if (bindingResult == null) {
			// Bean property binding and validation;
			// skipped in case of binding failure on construction.
			WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
			if (binder.getTarget() != null) {
				if (!mavContainer.isBindingDisabled(name)) {
                      // 绑定请求参数 也就是在这里将请求和对象绑定起来
					bindRequestParameters(binder, webRequest);
				}
				validateIfApplicable(binder, parameter);
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
					throw new BindException(binder.getBindingResult());
				}
			}
			// Value type adaptation, also covering java.util.Optional
			if (!parameter.getParameterType().isInstance(attribute)) {
				attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
			}
			bindingResult = binder.getBindingResult();
		}

		// Add resolved attribute and BindingResult at the end of the model
		Map<String, Object> bindingResultModel = bindingResult.getModel();
		mavContainer.removeAttributes(bindingResultModel);
		mavContainer.addAllAttributes(bindingResultModel);

		return attribute;
	}

上面我们看到了匹配的大概方法,这个依次递进贴绑定方法,会比较麻烦,可以通过IDEA打断点来查看,只要能找到其中遍历的那个代码就可以了

最后调用链

	@Nullable
	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 获取该方法的实参
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
        // 通过反射调用该方法
		return doInvoke(args);
	}

上面我们介绍了获取参数的方法 getMethodArgumentValues(),接下来我们看一下调用方法doInvoke()

	@Nullable
	protected Object doInvoke(Object... args) throws Exception {
         // 获取方法
		Method method = getBridgedMethod();
		ReflectionUtils.makeAccessible(method);
		try {
			if (KotlinDetector.isSuspendingFunction(method)) {
				return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
			}
             // 重点在这里 通过反射来调用方法
			return method.invoke(getBean(), args);
		}
		catch (IllegalArgumentException ex) {
			assertTargetBean(method, getBean(), args);
			String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
			throw new IllegalStateException(formatInvokeError(text, args), ex);
		}
		catch (InvocationTargetException ex) {
			// Unwrap for HandlerExceptionResolvers ...
			Throwable targetException = ex.getTargetException();
			if (targetException instanceof RuntimeException) {
				throw (RuntimeException) targetException;
			}
			else if (targetException instanceof Error) {
				throw (Error) targetException;
			}
			else if (targetException instanceof Exception) {
				throw (Exception) targetException;
			}
			else {
				throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
			}
		}
	}

我们已经说完了invokeForRequest()方法,获取到参数,成功调用方法,加下来继续回到invokeAndHandle()

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // 设置响应的状态码,这儿应该没有调用完,会是null
	setResponseStatus(webRequest);

    // 如果返回值为空
	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            // 禁用缓存
			disableContentCachingIfNecessary(webRequest);
            // 将这个变量设置为true
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	else if (StringUtils.hasText(getResponseStatusReason())) {// 这个有值
        // 将这个变量设置为true
		mavContainer.setRequestHandled(true);
		return;
	}

    // 请求需要处理
	mavContainer.setRequestHandled(false);
	Assert.state(this.returnValueHandlers != null, "No return value handlers");
	try {
        // 调用对应的方法处理返回值
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		if (logger.isTraceEnabled()) {
			logger.trace(formatErrorForReturnValue(returnValue), ex);
		}
		throw ex;
	}
}

上面的代码会调用handleReturnValue(),具体的代码如下:

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
		ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

    // 查找指定的方法返回值的处理器
	HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
	if (handler == null) {
		throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
	}
    // 调用指定的方法返回值的处理器中这个方法
	handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

上面的代码主要是通过selectHandler(returnValue, returnType);来查找对应的方法返回值的处理器,具体的代码如下:

private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
    // 判断是否是异步
	boolean isAsyncValue = isAsyncReturnValue(value, returnType);
    // 遍历所有的方法返回值的处理器的supportsReturnType方法,只要找到匹配的就直接返回
	for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
		if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
			continue;
		}
		if (handler.supportsReturnType(returnType)) {
			return handler;
		}
	}
	return null;
}

这儿原理和上面的找方法参数的处理器的机制差不多,都是遍历所有的处理器,调用对应处理器的supportsReturnType方法,一旦满足条件的话,就直接返回。

接下来我们继续回到invokeHandlerMethod(),我们在这个方法中已经调用了invokeAndHandle(),在该方法的的最后,又调用了getModelAndView()

	@Nullable
	private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

		modelFactory.updateModel(webRequest, mavContainer);
         // 判断这个值是否是true,一般返回的如果不是视图的话,这个值就是true
         // 因为我们现在的项目基本都是前后端分离,所以这里就直接返回了
		if (mavContainer.isRequestHandled()) {
			return null;
		}
		ModelMap model = mavContainer.getModel();
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			if (request != null) {
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
		}
		return mav;
	}

至此整个方法的调用的过程就讲完了,简单总结一下:

  1. 先根据方法的参数,遍历所有的参数处理器,分别调用处理器中的supportsParameter(),如果满足了就直接返回这个参数处理器,然后调用这个参数处理器的resolveArgument()
  2. 通过参数解析器获取到参数,接下来通过反射来调用方法
  3. 对方法的返回值进行处理,还是一样的先是遍历所有返回值处理器的,并且调用这些处理器中的supportsReturnType方法,如果满足的话,就直接返回这个处理器,同时会调用这个处理器的handleReturnValue方法对方法的返回值进行处理和封装

参数解析器初始化

上面我们用到了参数解析器,我们通过遍历,找到对应的参数解析器,那么这些参数解析器是如何初始化的呢?

我们之前提到 RequestMappingHandlerAdapter 这个类实现了 InitializingBean接口,当SpringMVC容器启动的适合,就会调用afterPropertiesSet()

	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBody advice beans
  		//初始化 @ControllerAdvice 注解需要的东西,后面写篇博客介绍下这个注解
		initControllerAdviceCache();

  		//获取调用的方法的参数
		if (this.argumentResolvers == null) {
        	//Spring提供的一系列的HandlerMethodArgumentResolver,同时这儿也会调用用户自己添加的HandlerMethodArgumentResolver
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
  		//获取桥接方法的参数
		if (this.initBinderArgumentResolvers == null) {
      		//Spring提供的一系列的HandlerMethodArgumentResolver,同时这儿也会调用用户自己添加的HandlerMethodArgumentResolver
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
  		//获取方法的返回的参数
		if (this.returnValueHandlers == null) {
      		//Spring提供的一系列的HandlerMethodReturnValueHandler,同时这儿也会调用用户自己添加的HandlerMethodReturnValueHandler
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}

我们上面用到的参数解析器 和 返回值处理器 就是在这里被初始化的。

	private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(20);

		// Annotation-based argument resolution
         // 注意看这里添加第一次RequestParamMethodArgumentResolver
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new SessionAttributeMethodArgumentResolver());
		resolvers.add(new RequestAttributeMethodArgumentResolver());

		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());

		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all
		resolvers.add(new PrincipalMethodArgumentResolver());
         // // 注意看这里添加第二次RequestParamMethodArgumentResolver
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));

		return resolvers;
	}

注意上面是加了两个RequestParamMethodArgumentResolver对象,只不过第一次的参数的值是false,第二次参数的值为true。那么这个两个值的区别是啥?我们还需要看 RequestParamMethodArgumentResolver 类的supportsParameter方法,具体的代码如下:

public boolean supportsParameter(MethodParameter parameter) {
     // 是否存在 RequestParam 注解
	if (parameter.hasParameterAnnotation(RequestParam.class)) {
		if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
			RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
			return (requestParam != null && StringUtils.hasText(requestParam.name()));
		}
		else {
			return true;
		}
	}
	else {
         // 是否存在RequestPart注解 该注解用于复杂的请求域
		if (parameter.hasParameterAnnotation(RequestPart.class)) {
			return false;
		}
		parameter = parameter.nestedIfOptional();
         // 是否是请求的参数
		if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
			return true;
		}
        // 区别在这,如果是true的话,基本的类型是会返回true 否则直接返回false
		else if (this.useDefaultResolution) {
			return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
		}
		else {
			return false;
		}
	}
}

上面两个RequestParamMethodArgumentResolver的区别就在于如果是true的话,基本的类型是会返回true,如果不是true,就直接跳过,代表我们匹配参数的时候,基本数据类型放到最后在匹配,优先匹配引用类型去匹配,也就是包装类的优先级高于基本数据类型

四、写在最后

HandlerAdapter 采用了适配器模式,主要是为了调用不同的接口方法,那么这里面最麻烦的就是RequestMappingHandlerAdapter,因为这个方法支持注解,而且要自动把参数赋值,这里面比较复杂的处理处理参数,需要长时间的看方法的调用

你可能感兴趣的:(SpringMVC,java)