spring基本使用(22)-springMVC6-SpringMVC九大组件之处理器映射器HandlerAdapter

1、前面一篇文章我们讲解了HandlerMapping的主流实现RequestMappingHandlerMapping处理器映射器,今天来剖析HandlerAdapter。RequestMappingHandlerMapping是主流使用的,那么对应肯定也有一个主流使用的RequestMappingHandlerAdapter,这个只是猜测,那么我们来spring-webmvc的源码中找一下看看,果不其然我们找到了如下图:

  没毛病,这就是目前主要使用的HandlerAdapter的实现。

 

2、我们知道HandlerMapping就是用来寻找一个HandlerExecutionChain即处理器执行链,里面封装了请求的拦截器,真正的处理器,而HandlerAdapter就是用来执行这个执行链的,也就是执行真正的处理器的,大白话一点就是Controller中的某个方法。

 

3、在DispatcherServlet的整个执行链路中,先获取到HandlerExecutionChain,然后在找到合适的HandlerAdapter来执行HandlerExecutionChain中的真正的处理器,套路就是这样搞。DispatcherServlet中的源码体现如下(片段):

// 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 = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
	long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
	if (logger.isDebugEnabled()) {
		logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
	}
	if (new ServletWebRequest(request, response).checkNotModified(lastModified)&&isGet) {
		return;
	}
}
执行拦截器的前置方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
	return;
}

// Actually invoke the handler.
使用找到的合适的HandlerAdapter来执行真正的处理器,并返回一个ModelAndView实例
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

applyDefaultViewName(processedRequest, mv);

执行拦截器的后置方法。
mappedHandler.applyPostHandle(processedRequest, response, mv);

 

4、整体流程我们知道了,那么我们来讨论两个问题,第一个:如何查找适合的处理器适配器HnadlerAdapter呢?

     第二个:处理器适配器HandlerAdapter是如何执行真正的处理器的呢?

 

.5、我们来解答第一个问题,如何根据真正的处理器来查找合适的处理器适配器。

     在DispatcherServlet中源码如下:

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
                循环DispatcherServlet实例的handlerAdapters列表
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
                        传入真正的处理器,看看当前的处理器适配器HandlerAdapter是否支持当前的处理器。
			if (ha.supports(handler)) {
                                如果支持就直接返回当前的处理器实例。
				return ha;
			}
		}
                如果都不支持,那就抛出异常。
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

        我们知道我们得到的真正的处理器类型是HandlerMethod类型的,我们来看看那些HandlerAdapter支持HandlerMethod类型的处理器,HandlerAdapter类图如下:

      在RequestMappingHandlerAdapter的父类AbstractHandlerMethodAdapter中的 supports(Object handler)方法如下:

	@Override
	public final boolean supports(Object handler) {
                如果handler是HandlerMethod类型的,并且内部支持HandlerMethod类型处理器,那就返回true
                这个supportsInternal方法是抽象方法,由RequestMappingHandlerAdapter实现。
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}


        在RequestMappingHandlerAdapter中的supportsInternal方法如下:
	@Override
	protected boolean supportsInternal(HandlerMethod handlerMethod) {
                直接返回true,表示支持类型是HandlerMethod类型的处理器
		return true;
	}

                 找处理器适配器HandlerAdapter的方式就是,循环调用拥有的处理器适配器的supports方法,如果返回true,那么就是用这个处理器映射器。

                 针对我们当前主要使用的实现就是RequestMappingHandlerAdapter实现类,其他的可以不用去深究。

 

6、接下来我们来剖析第二个问题,如何使用处理器适配器HandlerAdapter来执行真正的处理器。

      6.1、执行处理器在DispatcherServlet中的执行链路的源码体现:

        使用HandlerAdapter去执行真正的处理器
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

      6.2、我们使用的是RequestMappingHandlerAdapter来执行的,源码如下:

               在父类AbstractHandlerMethodAdapter中:

	@Override
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
                执行内部的处理方法,在RequestMappingHandlerAdapter中有具体的实现
		return handleInternal(request, response, (HandlerMethod) handler);
	}

                在RequestMappingHandlerAdapter中的内部执行处理器的方法源码:

	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
                第1步:将请求使用ServletWebRequest进行装饰。
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
                        第2步:使用handlerMethod去获取一个WebDataBinderFactory即web 数据绑定工厂。
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

                        第3步:使用参数绑定工厂+ 处理器 获取一个模型工厂ModelFactory。
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

                        第4步:使用处理器创建一个Servlet可调用的处理器实例
                              ServletInvocableHandlerMethod并设置其重要的属性
                              argumentResolvers、parameterNameDiscoverer、
                              returnValueHandlers、dataBinderFactory
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
                        invocableMethod.setHandlerMethodReturnValueHandl
                                                        ers(this.returnValueHandlers);
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

                        第5步:创建一个ModelAndViewContainer即ModelAndView的容器并初始化。
			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

                        第6步:对异步请求的支持条件构建。
			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();
				if (logger.isDebugEnabled()) {
					logger.debug("Found concurrent result value [" + result + "]");
				}
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}

                        第7步:执行处理器的方法。
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

                        第8步:返回ModelAndView。
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

              上面的RequestMappingHandlerAdapter的源码主要分为8个大步骤,接下来我们逐一进行详细分析:

                   第1步->将请求使用ServletWebRequest进行装饰, 为什么需要把HttpServletRequest装饰成为一个ServletWebRequest类型呢?原因是ServletWebRequest提供了请求头里的Last-Modified、If-Modified-Since、ETag的判定,可以做到如果请求资源没有任何改变,重复请求会告诉浏览器304 表示使用浏览器缓存的资源,关于这些请移步https://blog.csdn.net/Dongguabai/article/details/84323511

                   第2步->使用handlerMethod去获取一个WebDataBinderFactory即web 数据绑定工厂,这个地方很核心,表面意思就是获取一个WebDataBinderFactory即web数据绑定者工厂,我们来分析源码然后再谈谈工作机制:

                  类图:WebDataBinderFactory的作用就是用来创建并初始化一个WebDataBinder实例

                          

	private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
                 入参是HandlerMethod 实例
                 1、获取HandlerMethod 实例的beanType 其实就是Controller的class。
		Class<?> handlerType = handlerMethod.getBeanType();

                 2、从缓存中查找初始化的绑定者,什么是绑定者,待会详细说明。
		Set<Method> methods = this.initBinderCache.get(handlerType);
		if (methods == null) {
                        如果缓存中没有找到当前Controller中的绑定者,那就查找当前Controller中
                        的绑定者,此处的INIT_BINDER_METHODS入参是一个MethodFilter,就是控制
                        只查找Controller中被@InitBinder注解标注的方法。
			methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
			
                        找到后将其加入到缓存中,以提高效率,从这里可以看出来其实绑定者就是
                        Controller类中被@InitBinder注解标注的方法,一个方法对应一个绑定者。
			this.initBinderCache.put(handlerType, methods);
		}

                3、创建一个空集合用于存放InvocableHandlerMethod实例
		List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
		
		// Global methods first
		4、先找到全局的被@InitBinder的方法,从哪里找呢?就是从被@ControllerAdvice标注的类中去找。在RequsetMappingHandlerAdapter
		   初始化的时候会去解析全局的被@InitBinder的方法,然后添加到initBinderAdviceCache缓存中。
		for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
			if (entry.getKey().isApplicableToBeanType(handlerType)) {
				Object bean = entry.getKey().resolveBean();
				for (Method method : entry.getValue()) {
				    构建一个类型是InvocableHandlerMethod的可执行方法。
					initBinderMethods.add(createInitBinderMethod(bean, method));
				}
			}
		}
		
		5、然后再将当前的Controller类中的@InitBinder标注的方法构建为一个InvocableHandlerMethod实例添加到initBinderMethods集合的尾部。
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			initBinderMethods.add(createInitBinderMethod(bean, method));
		}
		
		6、构建一个类型是ServletRequestDataBinderFactory的数据绑定者工厂
		return createDataBinderFactory(initBinderMethods);
	}
	
	构建一个类型是InvocableHandlerMethod的可执行方法
	private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
	    直接new 一个InvocableHandlerMethod实例,使用initBinderMethod + Controller类||ControllerAdvice类。
		InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
		设置可执行方法的参数解析器
		binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
		
		设置可执行方法的数据绑定工厂为一个DefaultDataBinderFactory,
		入参webBindingInitializer实在注解驱动阶段设置的类型是ConfigurableWebBindingInitializer的实例。
		binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
		
		设置可执行方法的参数名称查找器
		binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		return binderMethod;
	}

                     WebDataBinder在初始化的过程中会调用被@InitBinder标注的方法。

                  第3步->使用第2步中获取到的参数绑定工厂+ 处理器 获取一个模型工厂ModelFactory,ModelFactory的作用就是用来执行被@ModelAttribute标注的方法以及处理@SessionAttribute注解的逻辑的,源码分析如下:

	private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
	        入参是HandlerMethod 实例 + 数据绑定工厂binderFactory
		1、获取SessionAttributesHandler即找到当前Controller类上标注的@SessionAttributes注解,
		   根据注解的属性构建一个SessionAttributesHandler。
		SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
		
		2、获取当前的Controller类的类型。
		Class<?> handlerType = handlerMethod.getBeanType();
		
		3、查找当前Controller类中被注解@ModelAttribute注解标注的方法并添加到modelAttributeCache缓存中
		Set<Method> methods = this.modelAttributeCache.get(handlerType);
		if (methods == null) {
			methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
			this.modelAttributeCache.put(handlerType, methods);
		}
		
		4、创建一个空集合用于存放可执行的方法实例
		List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
		// Global methods first
		
		5、先查找全局的被@ModelAttribute注解标注的方法,从哪里找呢?就是从被@ControllerAdvice标注的类中去找。在RequsetMappingHandlerAdapter
		   初始化的时候会去解析全局的被@ModelAttribute的方法,然后添加到modelAttributeAdviceCache缓存中。
		for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
			if (entry.getKey().isApplicableToBeanType(handlerType)) {
				Object bean = entry.getKey().resolveBean();
				for (Method method : entry.getValue()) {
				    构建一个类型是InvocableHandlerMethod的可执行方法。
					attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
				}
			}
		}
		
		6、然后再将当前的Controller类中的@ModelAttribute标注的方法构建为一个InvocableHandlerMethod实例添加到attrMethods集合的尾部。
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
		}
		
		7、使用attrMethods + 参数绑定工厂+SessionAttributesHandler实例来构建一个ModelFactory返回。
		return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
	}
	
	构建一个类型是InvocableHandlerMethod的可执行方法。
	private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
	
	    直接new 一个InvocableHandlerMethod实例,使用ModelAttributMethod + Controller类||ControllerAdvice类。
		InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
		
		设置可执行方法的参数解析器
		attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		
		设置可执行方法的参数名称查找器
		attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		
		设置可执行方法的数据绑定工厂。
		attrMethod.setDataBinderFactory(factory);
		return attrMethod;
	}

                 第4步->使用HandlerMethod实例创建一个ServletInvocableHandlerMethod并设置重要属性。

            创建一个ServletInvocableHandlerMethod实例,就是直接new
            ServletInvocableHandlerMethod invocableMethod = 
                     createInvocableHandlerMethod(handlerMethod);
            设置其参数解析器
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            设置其返回值处理器
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            设置其数据绑定工厂为第2步中构建的数据绑定工厂
            invocableMethod.setDataBinderFactory(binderFactory);
            设置其参数名称查找器			 
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

                 第5步:创建一个ModelAndViewContainer即ModelAndView的容器并初始化,我们主要查看初始化ModelAndViewContainer的流程。ModelAndViewContainer里面主要会存放view对象+model数据。

           直接new 一个ModelAndViewContainer实例
           ModelAndViewContainer mavContainer = new ModelAndViewContainer();
           添加数据到ModelAndViewContainer中的model中
           mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
           使用第3步构建的modelFactory初始化model,会执行@ModelAttribute方法以及SessionAttributeHandler方法。
           modelFactory.initModel(webRequest, mavContainer, invocableMethod);
           设置在重定向的时候忽列model
           mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

                         使用modelFactory来初始化model:

	public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
			throws Exception {
        
		1、先检查当前请求中的HttpSession中是否有@SessionAttributez注解定义的数据,如果有获取出来构建成一个Map,key=attributeName value=设置的值。
		Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
		
		2、合并session中的sessionAttributes数据,合并的意思就是使用session中的值替换掉ModelAndViewContainer中的model中同名称的值。
		container.mergeAttributes(sessionAttributes);
		
		3、执行被注解@ModelAttribute标注的方法,在构建ModelFactory的时候传入的解析好的attrMethod,
		在构建阶段会为使用其每一个InvocableHandlerMethod来构建一个ModelMethod实例,然后添加到ModelFactory的modelMethods集合中,
		在这一步会进行逐一调用。调用完成后会将返回值添加到ModelAndViewContainer中的model中。
		invokeModelAttributeMethods(request, container);

                4、查找当前的真正的处理器handlerMethod的method的参数是否标记了@ModelAttribute注解,
		for (String name : findSessionAttributeArguments(handlerMethod)) {
		    找到被注解@ModelAttribute标记的参数。
			if (!container.containsAttribute(name)) {
			    如果ModelAndViewContainer的model中不存在此属性值,那就去检索HttpSession中是否存在此值,如果没有直接抛出异常。
				Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
				如果session中有值
				if (value == null) {
					throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
				}
				如果HttpSession中存在此值,就加添加到ModelAndViewContainer中的model中。
				container.addAttribute(name, value);
			}
		}
	}

                                这个HttpSessionRequiredException异常在什么时候会抛出呢??? 案例如下:

              @Controller
              @RequestMapping("user")
              @SessionAttributes({"user", "userName"})
              public class UserController {
 
                  @ModelAttribute("user")
                  public User modelAttribute() {
                      User user = new User();
                      user.setUserId("1");
                      return user;
                  }
	
                  @RequestMapping("test")
                  public String test(@ModelAttribute("user") User user, @ModelAttribute("userName") String userName) {
                      参数userName在ModelAndViewContainer 的model中不存在,并且在HttpSession 
                      中也不存在,所有此处这样使用,在调用/user/test的时候会抛出
                      HttpSessionRequiredException。为什么user参数不会呢?因为执行到此处的时候
                      ModelAndViewContainer 的model中已经存在user属性了。
                      user.setUserId("2");
                      return "register";
                  }
              }

 

                第6步:对异步请求的支持条件构建,这一步没啥好说的,基本上不会使用。

                第7步:执行处理器HandlerMethod。

        invocableMethod.invokeAndHandle(webRequest, mavContainer);

                  ServletInvocableHandlerMethod(继承了InvocableHandlerMethod)类中:

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

                 1、执行处理器方法HandlerMethod
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		
                 2、设置响应状态
		setResponseStatus(webRequest);

                 3、处理返回值为空的情况
		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}

		mavContainer.setRequestHandled(false);
		
		4、使用返回值处理器对返回值进行处理
		try {
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
			}
			throw ex;
		}
	}

                   重点在执行处理器方法HandlerMethod : InvocableHandlerMethod类中

	public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

                1、获取方法参数值列表
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
					"' with arguments " + Arrays.toString(args));
		}
		2、执行真正的method方法,就是Controller中的方法。
		Object returnValue = doInvoke(args);
		if (logger.isTraceEnabled()) {
			logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
					"] returned [" + returnValue + "]");
		}
		return returnValue;
	}

                   获取方法参数值列表是个大步骤,SpringMVC/spring很多核心的组件都在这一步工作,比如ConversionService、Converter<S, T>、HttpMessageConverter<T>、PropertyEditor、Format等。

	private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

                1、获取HandlerMethod中的方法入参列表,在HnadlerMapping初始化的时候构建HandlerMethod的时候就以及解析好的了。
		MethodParameter[] parameters = getMethodParameters();
		
		2、创建一个方法入参value值的空数组,长度为方法入参的个数。
		Object[] args = new Object[parameters.length];
		
		3、循环绑定每一个方法入参的value值
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			3.1、初始化当前参数的名称发现者,默认是一个DefaultParameterNameDiscoverer。
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			
			3.2、从提供的providedArgs参数列表获取参数,默认providedArgs是空数组。
			args[i] = resolveProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			
			3.3、判断当前的参数解析器列表中,是否有能支持当前参数的 参数解析器,如果没有就会抛出IllegalStateException异常。
			if (this.argumentResolvers.supportsParameter(parameter)) {
				try {
				    3.4、如果有能够支持当前参数解析的 参数解析器,那就进行参数解析。
					args[i] = this.argumentResolvers.resolveArgument(
							parameter, mavContainer, request, this.dataBinderFactory);
					continue;
				}
				catch (Exception ex) {
					if (logger.isDebugEnabled()) {
						logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
					}
					throw ex;
				}
			}
			if (args[i] == null) {
				throw new IllegalStateException("Could not resolve method parameter at index " +
						parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
						": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
			}
		}
		
		3.5、所有参数解析完成后,就得到了方法的入参值列表返回。
		return args;
	}

                    上面源码中提到了InvocableMethod的参数解析器列表argumentResolvers,这个列表是什么时候初始化的呢?还记得在DispatcherServlet中构建了一个ServletInvocableHandlerMethod实例吗,ServletInvocableHandlerMethod继承了InvocableMethod类,在构建ServletInvocableHandlerMethod的时候设置了这个参数解析器列表argumentResolvers,设置的值就是RequestMappingHandlerAdapter中的argumentResolvers,也就是说                                                                                                          InvocableMethod.argumentResolvers=RequestMappingHandlerAdapter.argumentResolvers

              InvocableMethod.returnValueHandlers=RequestMappingHandlerAdapter.returnValueHandlers

              InvocableMethod.parameterNameDiscoverer=RequestMappingHandlerAdapter.parameterNameDiscoverer

              InvocableMethod.dataBinderFactor=ServletRequestDataBinderFactory实例

              那么RequestMappingHandlerAdapter.argumentResolvers实在什么时候设置的呢?RequestMappingHandlerAdapter实现了InitializingBean接口,在初始化的时候会设置一些默认的HandlerMethodArgumentResolver参数解析器,同时也会设置一下默认的返回结果处理器HandlerMethodReturnValueHandler,源码如下:

	@Override
	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBody advice beans
		1、初始化Controller通知类
		initControllerAdviceCache();

                2、初始化参数解析器列表
		if (this.argumentResolvers == null) {
		    获取默认的参数解析器列表,然后设置到当前RequestMappingHandlerAdapter的argumentResolvers属性。
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		
		3、初始化initBinder方法的参数解析器什么意思呢?就是说被注解@InitBinder标注的方法,
		   在调用的时候也需要进行参数解析,就是用initBinderArgumentResolvers这个里面的参数解析器进行入参绑定。
		if (this.initBinderArgumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		
		4、初始化返回结果处理器列表
		if (this.returnValueHandlers == null) {
		    获取默认的返回结果处理器列表并设置给当前RequestMappingHandlerAdapter的returnValueHandlers属性。
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}

                   获取默认的参数解析器列表:

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

		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));   支持@RequestParam注解标注的入参绑定,如下示例中的file参数也是使用此参数解析器,但是fileName不是,因为这个参数解析器
		                                                                                  的useDefaultResolution属性设置为了false,所以它不支持String fileName参数绑定。在下面还会添加一个同类型的RequestParamMethodArgumentResolver
																						  参数解析器用于支持String fileName这种基本类型的入参绑定。
		                                                                                     @RequestMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
                                                                                             private String upload(MultipartFile file, String fileName){
																							 
		resolvers.add(new RequestParamMapMethodArgumentResolver());                       支持@RequestParam注解标注的入参且类型是Map类型的入参绑定
		resolvers.add(new PathVariableMethodArgumentResolver());                          支持@PathVariable注解标注的入参绑定
		resolvers.add(new PathVariableMapMethodArgumentResolver());                       支持@PathVariable注解标注的入参且类型是Map类型的入参绑定
		resolvers.add(new MatrixVariableMethodArgumentResolver());                        支持@MatrixVariable注解标注的入参绑定
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());                     支持@MatrixVariable注解标注的入参类型是Map类型的入参绑定
		resolvers.add(new ServletModelAttributeMethodProcessor(false));                   支持常规的封装类型入参如Huma huma 也支持@ModelAttribute注解标注的入参绑定
		                                                                                      案例:@RequestMapping("test")
																						            public String test(Huma huma) {
		
		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));   支持@RequestBody标注的入参绑定,
		                              同时也是一个返回结果处理器,支持方法被@ResponseBody标注的方法,这个处理器需要使用HttpMessageConverters来进行body里面的数据与参数类型的转换。
									  同时这个参数解析器还需要使用requestResponseBodyAdvice 通知类列表在read 数据前后进行通知,我们可以在利用这个特性进行扩展。
									  !!!!HttpMessageConverters 只会在入参是@RequestBody、@ResponseBody的这种方式下会使用到,其他方式都是使用Converter<S, T>来进行入参绑定。
									  
		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));    支持@RequestPart标注的入参绑定,一般用于文件上传的请求
		                                                                                       @RequestMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
                                                                                               private String upload(@RequestPart("file") MultipartFile file, String fileName){
		
		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));              支持@RequestHeader标注的入参绑定,用于从请求头中获取参数进行绑定
		resolvers.add(new RequestHeaderMapMethodArgumentResolver());                           支持@RequestHeader标注的入参绑且类型是Map类型的入参绑定,用于从请求头中获取参数进行绑定
		resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));         支持@CookieValue注解标注的入参绑定
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));            支持@Value标注的入参绑定,绑定的时候进行表达式计算
		resolvers.add(new SessionAttributeMethodArgumentResolver());                           支持@SessionAttribute标注的入参绑定,用于从HttpSession中获取数据进行绑定
		resolvers.add(new RequestAttributeMethodArgumentResolver());                           支持@RequestAttribute标注的入参绑定,其实就是获取request的属性,与request.getParameter(“name”)不一样哈。
		                                                                                        案例:
																		                           @RequestMapping("/httpServletRequestParam")
                                                                                                   public String httpServletRequestParam(HttpServletRequest request,
                                                                                                                       @RequestAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT") Object o){

                                                                                                      WebApplicationContext attribute = (WebApplicationContext) request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
                                                                                                      System.out.println(o==attribute);  //结果输出为true
                                                                                                      return  "register";
                                                                                                   }
 
		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());                             支持入参类型是WebRequest、ServletRequest、MultipartRequest、HttpSession、Principal
		                                                                                                 InputStream、Reader、HttpMethod、Locale、TimeZone 或者参数名称="ava.time.ZoneId" 类型的入参
																										 其含义就是取请求request对象或者request对象的属性进行入参绑定。
																										  
		resolvers.add(new ServletResponseMethodArgumentResolver());                            支持入参类型是ServletResponse、OutputStream、Writer其含义就是取请求response对象或者response对象的属性进行入参绑定。
		
		resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));  支持入参类型是HttpEntity、RequestEntity的入参绑定
		resolvers.add(new RedirectAttributesMethodArgumentResolver());                         支持入参类型是RedirectAttributes的入参绑定
		resolvers.add(new ModelMethodProcessor());                                             支持入参类型是Model的入参绑定
		resolvers.add(new MapMethodProcessor());                                               支持入参是Map类型的入参绑定
		resolvers.add(new ErrorsMethodArgumentResolver());                                     支持入参是org.springframework.validation.Errors类型的入参绑定,SpringMVC的验证结果BindingResult就是继承了Errors。
		resolvers.add(new SessionStatusMethodArgumentResolver());                              支持入参类型是SessionStatus的入参绑定,其含义是直接获取 ModelAndViewContainer实例的SessionStatus实例进行入参绑定
		resolvers.add(new UriComponentsBuilderMethodArgumentResolver());                       支持入参类型是UriComponentsBuilder、ServletUriComponentsBuilder的入参绑定,
		                                                                                           其含义就是将使用构建请求uri的 uri组件构建者获取到绑定到入参上,我们可以使用UriComponentsBuilder取获取请求uri的信息
																								   案例:
																								     @RequestMapping(value = "uriComponentsBuilderTest")
                                                                                                     private String UriComponentsBuilderTest(UriComponentsBuilder uriComponentsBuilder,
                                                                                                                                             ServletUriComponentsBuilder servletUriComponentsBuilder){
                                                                                                            System.out.println(uriComponentsBuilder.toUriString());
                                                                                                            System.out.println(servletUriComponentsBuilder.toUriString());
                                                                                                            return "register";
                                                                                                     }
																									 输出如下:
																									   http://localhost:7070
                                                                                                       http://localhost:7070
                添加自定义的参数解析器
		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all
		在添加一个RequestParamMethodArgumentResolver且为默认处理基本类型的参数解析器,在上面已经添加了一个同类型的,只是默认不处理基本类型
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
		再添加一个注解不是必须的ServletModelAttributeMethodProcessor参数解析器,也就是说没有@ModelAttribute注解的封装类型支持 如User user类型入参绑定
		resolvers.add(new ServletModelAttributeMethodProcessor(true));

		return resolvers;
	}

                        上面这段源码太长,建议读者自己拷贝出来阅读,这就是RequestMappingHandlerAdapter初始化参数解析器列表的主要实现。

                  接着主流程走,找到相应支持当前参数的参数解析器后,那就是用其参数解析器就行参数value的解析,然后将参数的value值添加到方法的入参数组中。我们讲解两个重要且常用的参数解析器:

                       第一个:RequestParamMethodArgumentResolver(getBeanFactory(), false) 

                       第二个:RequestResponseBodyMethodProcessor

          RequestParamMethodArgumentResolver(getBeanFactory(), false) 实现原理分析:

                 类图:继承了抽象的AbstractNamedValueMethodArgumentResolver

                                

                  解析参数的方法实现:RequestParamMethodArgumentResolver 来说,解析参数的方法在父类AbstractNamedValueMethodArgumentResolver中:

                  AbstractNamedValueMethodArgumentResolver中源码如下:

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

               1、构建一个NamedValueInfo实例 实例包含参数名称name、是否是必须required、
                 defaultValue 三个信息,会进行缓存NamedValueInfo实例方便下一次调用的时候提高 
                 性能。getNamedValueInfo方法中调用了createNamedValueInfo(MethodParameter 
                 parameter)抽象方法,具体的实现由RequestParamMethodArgumentResolver实现
		 NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);解决参数嵌套 
                 就是检查参数是否是Java8 的java.util.Optional类型,如果是就解析嵌套。
		MethodParameter nestedParameter = parameter.nestedIfOptional();
        
		2、解析参数名称
		Object resolvedName = resolveStringValue(namedValueInfo.name);
		if (resolvedName == null) {
			throw new IllegalArgumentException(
					"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
		}

                3、解析参数值,是抽象方法,具体的实现由RequestParamMethodArgumentResolver实现,这里我们不再细看,针对RequestParamMethodArgumentResolver就如下事情:
		   如果是上传文件请求,解析文件,否则就直接 request.getParameterValues(name);获取入参的字符串,如果请求中存在多个名称相同的入参,则返回字符串数组。
		Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
		
		if (arg == null) {
		        如果从请求中获取到参数,且有默认值,那就解析默认值
			if (namedValueInfo.defaultValue != null) {
				arg = resolveStringValue(namedValueInfo.defaultValue);
			}
			如果从请求中获取到参数,且参数是必须的且不是Java8 的java.util.Optional,那就抛出异常MissingServletRequestPartException
			异常的message="Required request part '" + partName + "' is not present" 这个错误应该是不叫出名的吧!!
			else if (namedValueInfo.required && !nestedParameter.isOptional()) {
				handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
			}
			处理默认值,比如是Boolean类型的话,那就赋值为false,目前只针对Boolean进行了默认值赋值。
			arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
		}
		
		如果参数值是empty 字符串 且参数的默认值不为空
		else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
		        那就使用默认值赋值给入参
			arg = resolveStringValue(namedValueInfo.defaultValue);
		}

                4、如果参数值获取到了且binderFactory 参数绑定者工厂不为空,那就创建参数绑定器进行参数绑定。
		if (binderFactory != null) {
		    使用binderFactory创建参数绑定器DataBinder,WebDataBinder继承自DataBinder,根据整体的调用链跟踪下来我们的binderFactory 类型是ServletRequestDataBinderFactory
			WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
			try {
			    使用binder进行参数转换,其实就是返回Controller的方法入参,也许有人会问,前面不是拿到请求的参数了吗?为什么还需要进行参数转换,
				原因就是请求里面的参数都是字符类型的,如果我们接受的不是字符类型,比如数字,集合,包装类型的数据,那么就需要进行入参转换了,这
				就是参数绑定者binder的作用。
				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());

			}
		}
                处理器已经转换的参数,这里在PathVariableMethodArgumentResolver有实现,其他的参数解析器目前没有任何操作。
		handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

		return arg;
	}

                  上面源码中我们看到了使用WebDataBinderFactory来创建一个数据绑定者binder

                  WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);

                  我们知道来看看实现是什么,在前面我们已经介绍了WebDataBinderFactory的整体类结构:

                  在DefaultDataBinderFactory中:

	@Override
	public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
			throws Exception {
               1、创建一个绑定者,就是直接new ExtendedServletRequestDataBinder, 
		是因为我们的WebDataBinderFactory类型是ServletRequestDataBinderFactory,
		所以创建的过程在ServletRequestDataBinderFactory中。
		objectName是参数名称,target是null,webRequest就是我们的请求。
		WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
		if (this.initializer != null) {
		    如果当前的DataBinderFactory 绑定者工厂的属性	private final WebBindingInitializer initializer;不为空,那就初始化绑定初始者。
			initializer我们是在解析注解驱动的时候给RequestMappingHandlerAdapter设置的时候设置了handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
			默认使用的实现是ConfigurableWebBindingInitializer实例,当然我们也可以自定义。
			this.initializer.initBinder(dataBinder, webRequest);
		}
		
		2、初始化创建的绑定者(区分三个角色WebDataBinderFactory:绑定者工厂,专门由于构建绑定者。
		                             WebBindingInitializer : 绑定初始化者,专门用于初始化绑定者。
				             WebDataBinder:真正的绑定者,复杂数据转换工作。)
		初始化绑定者的时候会调用之前解析好的@InitBinder标注的方法。
		 案例:
		     @InitBinder
                     private void configDataBinder(WebDataBinder webDataBinder) {
                        //给当前的绑定者注册自定义属性编辑器,注意方法一定要使用@InitBinder标注。此编辑器的作用域只是当前的Controller类中。
                        //注册到dataBinder的SimpleTypeConverter属性的customerEditors的集合中。
                        webDataBinder.registerCustomEditor(Person.class, new PersonEditor111());
                     }
		initBinder(dataBinder, webRequest);
		
		返回初始化好的绑定者
		return dataBinder;
	}

                   类图:

                            

                            类图可以看出DataBinder是WebDataBinder的父类,我们来看看DataBinder的重要属性:

             public class DataBinder implements PropertyEditorRegistry, TypeConverter {
                public static final String DEFAULT_OBJECT_NAME = "target";
                public static final int DEFAULT_AUTO_GROW_COLLECTION_LIMIT = 256;
                protected static final Log logger = LogFactory.getLog(DataBinder.class);
                private static Class<?> javaUtilOptionalClass = null;
                private final Object target;                           一般是null
                private final String objectName;                       当前处理的参数名称,也就是说一个入参会对应一个DataBinder实例
                private AbstractPropertyBindingResult bindingResult;
                private SimpleTypeConverter typeConverter;             常规的类型转换器,这里
                private boolean ignoreUnknownFields;
                private boolean ignoreInvalidFields;
                private boolean autoGrowNestedPaths;
                private int autoGrowCollectionLimit;
                private String[] allowedFields;
                private String[] disallowedFields;
                private String[] requiredFields;
                private ConversionService conversionService;           转换服务
                private MessageCodesResolver messageCodesResolver;     消息code解析器
                private BindingErrorProcessor bindingErrorProcessor;   绑定错误处理器,默认是DefaultBindingErrorProcessor实例
                private final List<Validator> validators;              验证器列表

                           接下来我们分析DataBinder是如何进行入参转换的:

                           DataBinder中:

           public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException {
              先获取到DataBinder的SimpleTypeConverter实例,然后进行类型转换
              return this.getTypeConverter().convertIfNecessary(value, requiredType, methodParam);
           }

                        SimpleTypeConverter父类TypeConverterSupport中:

              public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException {
                 找到doConvert方法进行参数类型转换。
                 return this.doConvert(value, requiredType, methodParam, (Field)null);
              }

 

            private <T> T doConvert(Object value, Class<T> requiredType, MethodParameter methodParam, Field field) throws TypeMismatchException {
               try {
                   使用TypeConverterSupport中的typeConverterDelegate进行参数类型转换
                   return field != null ? this.typeConverterDelegate.convertIfNecessary(value, requiredType, field) : this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
               } catch (ConverterNotFoundException var6) {
                  throw new ConversionNotSupportedException(value, requiredType, var6);
               } catch (ConversionException var7) {
                  throw new TypeMismatchException(value, requiredType, var7);
               } catch (IllegalStateException var8) {
                  throw new ConversionNotSupportedException(value, requiredType, var8);
               } catch (IllegalArgumentException var9) {
                  throw new TypeMismatchException(value, requiredType, var9);
               }
           }

                        TypeConverterDelegate是TypeConverterSupport中的一个属性作用就是代理类型转换任务,TypeConverterDelegate中的private final PropertyEditorRegistrySupport propertyEditorRegistry; 属性值就是SimpleTypeConverter实例,接着流程往下走:

                        TypeConverterDelegate中:

             public <T> T convertIfNecessary(Object newValue, Class<T> requiredType, MethodParameter methodParam) throws IllegalArgumentException {
                return this.convertIfNecessary((String)null, (Object)null, newValue, requiredType, methodParam != null ? new TypeDescriptor(methodParam) : TypeDescriptor.valueOf(requiredType));
             }

                            下面这个方法比较长,是真正处理类型转换的逻辑:

    public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
	从SimpleTypeConverter 中通过参数类型获取到自定义的属性编辑器,
        也就是我们可以手动的通过WebDataBinder去注册自己想要的属性编辑器。
        PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
        ConversionFailedException conversionAttemptEx = null;
		
	从SimpleTypeConverter 中获取到类型转换服务conversionService,这个我们在注解驱动是时候可配
     置 <mvc:annotation-driven conversion-service="conversionService" >如果不配置的话会配置 
     一个默认的FormattingConversionServiceFactoryBean,conversionService这个bean会初始化好 
    很多默认的Converter<S, T>,如StringToBooleanConverter、StringToLocaleConverter等等
        ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
		
        如果没有找到参数类型相关的属性编辑器器,但是找到了conversionService,那就使用conversionService进行类型转换。
        if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
            TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
			 
           如果没有找到属性编辑器的话,但是找到了conversionService的话,那就循环去判断 
           conversionService中的所有的Converter转换器,谁支持入参的类型就是用谁进行类型转换。
           还记得都写过的Date入参的类型转换吗?原因就是因为conversionService默认是没有Date类型的Converter的。
            if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                try {
                    return conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                } catch (ConversionFailedException var14) {
                    conversionAttemptEx = var14;
                }
            }
        }

        Object convertedValue = newValue;
		
        如果属性类型相关的编辑器存在
        if (editor != null || requiredType != null && !ClassUtils.isAssignableValue(requiredType, newValue)) {
            如果参数类型是集合,且请求里面的参数值是String类型,那就split(",")得到一个数组赋值到convertedValue。
            if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) && newValue instanceof String) {
                TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
                if (elementTypeDesc != null) {
                    Class<?> elementType = elementTypeDesc.getType();
                    if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String)newValue);
                    }
                }
            }
            
            如果没有找到用户自定义的属性编辑器,那就去寻找默认的属性编辑器,此处也就是SpringMVC支持JavaBean规范的地方
            if (editor == null) {
                editor = this.findDefaultEditor(requiredType);
            }
            使用找到的属性编辑器进行入参类型转换。此处不在细看,很简单,就是调用编辑器的方法而已。
            convertedValue = this.doConvertValue(oldValue, convertedValue, requiredType, editor);
        }

        如果通过以上匹配未发现相关的属性编辑器或者Converter那就兜底处理,此处大致过一下,感兴趣的可以深究一下。主要掌握 Editor 和 Converter 的作用就好。
        boolean standardConversion = false;
        if (requiredType != null) {
            if (convertedValue != null) {
                如果入参是Object类型,直接返回请求里的值
                if (Object.class == requiredType) {
                    return convertedValue;
                }

                如果是数组,那就转换为数组
                if (requiredType.isArray()) {
                    if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String)convertedValue);
                    }

                    return this.convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
                }

                如果是集合那就转换为集合类型
                if (convertedValue instanceof Collection) {
                    convertedValue = this.convertToTypedCollection((Collection)convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
					
                如果是Map那就转换为Map类型
                } else if (convertedValue instanceof Map) {
                    convertedValue = this.convertToTypedMap((Map)convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                }

                if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
                    convertedValue = Array.get(convertedValue, 0);
                    standardConversion = true;
                }

                if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
                    return convertedValue.toString();
                }

                if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
                    if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
                        try {
                            Constructor<T> strCtor = requiredType.getConstructor(String.class);
                            return BeanUtils.instantiateClass(strCtor, new Object[]{convertedValue});
                        } catch (NoSuchMethodException var12) {
                            if (logger.isTraceEnabled()) {
                                logger.trace("No String constructor found on type [" + requiredType.getName() + "]", var12);
                            }
                        } catch (Exception var13) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", var13);
                            }
                        }
                    }

                    String trimmedValue = ((String)convertedValue).trim();
                    if (requiredType.isEnum() && "".equals(trimmedValue)) {
                        return null;
                    }

                    convertedValue = this.attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
                    standardConversion = true;
                } else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
                    convertedValue = NumberUtils.convertNumberToTargetClass((Number)convertedValue, requiredType);
                    standardConversion = true;
                }
            } else if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
                convertedValue = javaUtilOptionalEmpty;
            }

            if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
                if (conversionAttemptEx != null) {
                    throw conversionAttemptEx;
                }

                if (conversionService != null) {
                    TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
                    if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                        return conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                    }
                }

                StringBuilder msg = new StringBuilder();
                msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
                msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
                if (propertyName != null) {
                    msg.append(" for property '").append(propertyName).append("'");
                }

                if (editor != null) {
                    msg.append(": PropertyEditor [").append(editor.getClass().getName()).append("] returned inappropriate value of type '").append(ClassUtils.getDescriptiveType(convertedValue)).append("'");
                    throw new IllegalArgumentException(msg.toString());
                }

                msg.append(": no matching editors or conversion strategy found");
                throw new IllegalStateException(msg.toString());
            }
        }

        if (conversionAttemptEx != null) {
            if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
                throw conversionAttemptEx;
            }

            logger.debug("Original ConversionService attempt failed - ignored since PropertyEditor based conversion eventually succeeded", conversionAttemptEx);
        }

        return convertedValue;
    }

                   讲完RequestParamMethodArgumentResolver(getBeanFactory(), false)接下来我们来分析RequestResponseBodyMethodProcessor:

                    老规矩先看类图:

                       

                       从类图可以看出RequestResponseBodyMethodProcessor即是也是一个ArgumentResovler也是一个ReturnValueHandler, 在上面我们知道RequestResponseBodyMethodProcessor支持的入参是@RequestBody标注的入参,支持的返回值处理的方式是方法被注解@ResponseBody标注的方法。

                       我们的messageConverters列表是在什么时候初始化的呢?

                       这个问题其实之前已经讲过,那就是在RequestMappingHandlerAdapter在构建BeanDefinition实例的时候赋值的,在注解驱动解析阶段的源码体现如下:

         
         此处会添加一下默认的HttpMessageConverteter,比如:
              ByteArrayHttpMessageConverter
              StringHttpMessageConverter
              ResourceHttpMessageConverter
              SourceHttpMessageConverter
              AllEncompassingFormHttpMessageConverter
              还会查看类路径下是否有jackson相关的依赖,如果有也会默认添加:
                   MappingJackson2HttpMessageConverter
                   MappingJackson2XmlHttpMessageConverter
              等等。。。
         ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);

         handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);

                       接下来详细分析RequestResponseBodyMethodProcessor的实现方式我们只需要从resolveArgument方法开始,之前的寻找参数解析器的流程是一致的:

                     RequestResponseBodyMethodProcessor中:

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

                同样判断如果入参类型是java.util.Optional类型的话获取到真正的类型
		parameter = parameter.nestedIfOptional();
		
		使用已有的HttpMessageConverter进行请求体里的数据读取,读取的方式就是循环匹配,查看哪一个HttpMessageConverter支持当前入参类型的读取,
		如果有能够读取的HttpMessageConverter那就调用其read 方法得到入参类的value值返回
		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
		
		获取入参参数的名称
		String name = Conventions.getVariableNameForParameter(parameter);

                再创建一个WebDataBinder实例,为什么会创建WebDataBinder实例呢?是不是很奇怪,那是因为SpringMVC吧参数检验的校验器封装到了WebDataBinder实例中,
		因此还需要创建一个WebDataBinder实例来进行入参校验,所以才创建了一个WebDataBinder实例。
		WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
		if (arg != null) {
		    使用WebDataBinder实例进行入参检验
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
				throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
			}
		}
		把校验结果添加到ModelAndViewContainer实例中
		mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());

                返回适配结果,这里如果入参是java.util.optional的话会给真正的入参赋值。
		return adaptArgumentIfNecessary(arg, parameter);
	}

                  readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()):

                   parameter.getNestedGenericParameterType()这个值就是入参的参数类型:

	@Override
	protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
			Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

                获取到被包装过的HttpServletRequest请求实例
		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
		
		使用上面获取到的HttpServletRequest请求实例来构建一个ServletServerHttpRequest实例,
		创建一个ServletServerHttpRequest的作用是,ServletServerHttpRequest类提供了获取请求体body
		的功能,返回的是一个InputStream 输入流。
		ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);

                正式使用MessageConverters列表进行请求体处理
		Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
		if (arg == null) {
			if (checkRequired(parameter)) {
				throw new HttpMessageNotReadableException("Required request body is missing: " +
						parameter.getMethod().toGenericString());
			}
		}
		return arg;
	}

                   

	protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
			Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

		MediaType contentType;
		boolean noContentType = false;
		try {
		        从请求头中获取到内容的类型,如果获取出错就抛出HttpMediaTypeNotSupportedException异常,也就是媒体类型不支持。
			contentType = inputMessage.getHeaders().getContentType();
		}
		catch (InvalidMediaTypeException ex) {
			throw new HttpMediaTypeNotSupportedException(ex.getMessage());
		}
		if (contentType == null) {
		        如果没有获取到contentType,那么默认就设置为application/octet-stream 类型
			noContentType = true;
			contentType = MediaType.APPLICATION_OCTET_STREAM;
		}

                获取到上下文的Class类型,其实就是获取Controller类的类型
		Class<?> contextClass = (parameter != null ? parameter.getContainingClass() : null);
		Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
		if (targetClass == null) {
			ResolvableType resolvableType = (parameter != null ?
					ResolvableType.forMethodParameter(parameter) : ResolvableType.forType(targetType));
			targetClass = (Class<T>) resolvableType.resolve();
		}

                获取请求方式如GET、POST等请求方式
		HttpMethod httpMethod = ((HttpRequest) inputMessage).getMethod();
		
		先赋值一个body变量=new Object();
		Object body = NO_VALUE;

		try {
		
		        使用HttpInputMessage实例来构建一个EmptyBodyCheckingHttpInputMessage实例,其实就是检查是否是空数据。
			inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);

                        循环HeepMessageConverter列表,找到能够处理当前入参类型的
                        messageConverter来进行数据的读取与类型转换。具体的api可以查看 
                        HttpMessageConverter<T>接口
                        我们常用的MappingJackson2HttpMessageConverter、
                        MappingJackson2XmlHttpMessageConverter就是在这里工作的。
			for (HttpMessageConverter<?> converter : this.messageConverters) {
			
			    获取到当前循环的HttpMessageConverter的类型
				Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
				if (converter instanceof GenericHttpMessageConverter) {
				    如果当前循环的HttpMessageConverter的类型是GenericHttpMessageConverter类型那就强转为GenericHttpMessageConverter类型也就是通用的处理器
					GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
					
					然后使用强转后的GenericHttpMessageConverter类型进行可读性判断。
					if (genericConverter.canRead(targetType, contextClass, contentType)) {
						if (logger.isDebugEnabled()) {
							logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
						}
						
						如果当前循环GenericHttpMessageConverter类型可读当前的请求体,且请求体不为空,那就进行读取。
						if (inputMessage.getBody() != null) {
						    读取之前先获取到通知,这里的通知类就是在RequestMappingHandlerAdapter初始化的时候会初始化这些通知类,规则就是在容器中
							查找被注解@ControllerAdvice标注的且类型是RequestBodyAdvice 或者 ResponseBodyAdvice 类型的通知。
							
							如果有RequestBodyAdvice 的话就按顺序调用其beforeBodyRead方法进行读前处理。
							inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
							
							使用genericConverter来读取body并转化为入参的目标类型 得到一个入参的value值。
							body = genericConverter.read(targetType, contextClass, inputMessage);
							
							如果有RequestBodyAdvice 的话就按顺序调用其afterBodyRead方法进行读后处理
							body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
						}
						else {
						    如果body是空的,那就使用找到的RequestBodyAdvice进行handleEmptyBody 空body处理。
							body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
						}
						break;
					}
				}
				如果当前循环的HttpMessageConverter不是通用的处理器,比如ByteArrayHttpMessageConverter就只支持入参类型是字节数组byte[]
				else if (targetClass != null) {
				    如果不是通用的处理器,那就判断当前处理器是否支持当前的入参类型
					if (converter.canRead(targetClass, contentType)) {
						if (logger.isDebugEnabled()) {
							logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
						}
						如果支持且body不为空那就使用当前处理器进行body的读取与类型转换。
						if (inputMessage.getBody() != null) {
							inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
							body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
							body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
						}
						else {
							body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
						}
						break;
					}
				}
			}
		}
		catch (IOException ex) {
		         如果在寻找处理器或者使用处理器进行body读取以及类型转换的过程中出错的话就直接抛出HttpMessageNotReadableException异常。
			throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
		}

                如果经过以上的操作还是没有正确的进行body读取以及类型转换的话
		if (body == NO_VALUE) {
		        那就判断请求方法类型是否为空 或者请求的方式是不支持的 或者 contentType+body是空的话 那就直接返回null 表示当前的入参值是null
			if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
					(noContentType && inputMessage.getBody() == null)) {
				return null;
			}
			
			否则抛出异常HttpMediaTypeNotSupportedException 媒体类型不支持
			throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
		}

                如果读取以及参数类型转换正确那就返回转换好的入参value值。
		return body;
	}

                     这就是整个RequestResponseBodyMethodProcessor参数解析器的工作原理。

          参数解析器分析完成,我们接着第7步分析,参数解析完成后我们得到了参数列表,接下来正式调用HandlerMethod 也就是Controller中的方法,也就是这一步Object returnValue = doInvoke(args):

                    InvocableHandlerMethod中:

	protected Object doInvoke(Object... args) throws Exception {
		ReflectionUtils.makeAccessible(getBridgedMethod());
		try {
		        获取到泛型操作安全的桥接方法,也就是真正的Controller中的方法,只是说进行了泛型安全桥接。
			return getBridgedMethod().invoke(getBean(), args);
		}
		catch (IllegalArgumentException ex) {
			assertTargetBean(getBridgedMethod(), getBean(), args);
			String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
			throw new IllegalStateException(getInvocationErrorMessage(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 {
				String text = getInvocationErrorMessage("Failed to invoke handler method", args);
				throw new IllegalStateException(text, targetException);
			}
		}
	}

                    真正的Controller中的方法执行完成后会进行返回值处理,此时之前配置的返回值处理器就排上了用场,至于这一块的细节实现,自己去看吧,比较简单。

 

          第8步: 返回ModelAndView。
                        return getModelAndView(mavContainer, modelFactory, webRequest);

                        在RequestMappingHandlerMapping中:

	private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
        
		这一步就是把之前执行的被注解@ModelAttribute注解标注的方法的返回值去绑定到sessionAttributesHandler去进行存储,
		当然前提是你使用了@SesssionAttribute注解进行model存储在session中前提是你使用了@SesssionAttribute注解进行model存储在session中
		modelFactory.updateModel(webRequest, mavContainer);
		if (mavContainer.isRequestHandled()) {
			return null;
		}
		
		从ModelAndViewContainer实例中获取到model
		ModelMap model = mavContainer.getModel();
		
		创建一个ModelAndView实例
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
		
		如果model是重定向参数那就特殊操作。
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
		}
		return mav;
	}

 

   这就是RequestMappingHandlerAdapter的整体工作原理,我们对核心部分进行了源码剖析,整体还是比较复杂的,我们掌握好核心的原理就好,至于很多小细节处理不需要过度关心。

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值