【Spring】抽丝剥茧SpringMVC-参数解析器HandlerMethodArgumentResolver

源码基于SpringMVC 5.2.7

HandlerMethodArgumentResolver

HandlerMethodArgumentResolver是参数解析器的接口类,其主要有2个方法

boolean supportsParameter(MethodParameter parameter)

  • 功能:检测该解析器是否支持给定的参数

Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory)

  • 功能:从给定的webRequest中解析出与parameter匹配的值
  • 参数mavContainer:提供了对model的访问方法
  • 参数binderFactory:DataBinder工厂,用来创建DataBinder

SpringMVC框架提供了很多参数解析,如下表所示

类型支持的参数条件备注

org.springframework.web.method.annotation

.RequestParamMethodArgumentResolver

参数符合以下任一条件

1. 被@RequestParam注解且参数类型不是Map

2. 被@RequestParam注解且参数类型是Map且@RequestParam注解的name属性不为空

3. 没有注解@RequestParam且没有注解@RequestPart且参数是MultipartFile或part(与multipart requests相关)

4. 如果解析器作为默认解析器即useDefaultResolution为true且参数类型是简单类型

任一条件满足即支持

org.springframework.web.method.annotation

.RequestParamMapMethodArgumentResolver

参数包含注解@RequestParam且类型是Map及其子类且注解@RequestParam属性的name为空

 

org.springframework.web.servlet.mvc.method.annotation

.PathVariableMethodArgumentResolver

该解析支持符合以下条件任一条件的参数

1. 参数包含注解@PathVariable且参数类型不是Map及其子类

2. 参数包含注解@PathVariable且参数类型是Map及其子类且注解@PathVariable的value属性不为空

 

org.springframework.web.servlet.mvc.method.annotation

.PathVariableMapMethodArgumentResolver

参数包含注解@PathVariable且类型是Map及其子类且注解@PathVariable属性的name为空

 

org.springframework.web.servlet.mvc.method.annotation

.MatrixVariableMethodArgumentResolver

该解析支持符合以下条件任一条件的参数

1. 参数包含注解@MatrixVariable且参数类型不是Map及其子类

2. 参数包含注解@MatrixVariable且参数类型是Map及其子类且注解@MatrixVariable的value属性不为空

 

org.springframework.web.servlet.mvc.method.annotation

.MatrixVariableMapMethodArgumentResolver

参数包含注解@MatrixVariable且类型是Map及其子类且注解@MatrixVariable属性的name为空

 

org.springframework.web.servlet.mvc.method.annotation

.ServletModelAttributeMethodProcessor

参数符合以下任一条件

1. 参数有注解@ModuleAttribute

2. 属性annotationNotRequired为true且参数不是简单类型,简单类型包括

 

org.springframework.web.servlet.mvc.method.annotation

.RequestResponseBodyMethodProcessor

参数包含注解@RequestBody

 

org.springframework.web.method.annotation

.RequestHeaderMethodArgumentResolver

 参数包含注解@RequestHeader且参数类型不是Map及其子类

 

org.springframework.web.method.annotation

.RequestHeaderMapMethodArgumentResolver

参数包含注解@RequestHeader且类型是Map及其子类

 

org.springframework.web.servlet.mvc.method.annotation

.ServletCookieValueMethodArgumentResolver

参数包含注解@CookieValue

 

org.springframework.web.method.annotation

.ExpressionValueMethodArgumentResolver

参数包含注解@Value

 

org.springframework.web.servlet.mvc.method.annotation

.SessionAttributeMethodArgumentResolver

参数包含注解@SessionAttribute

 

org.springframework.web.servlet.mvc.method.annotation

.RequestAttributeMethodArgumentResolver

参数包含注解@RequestAttribute

 

org.springframework.web.servlet.mvc.method.annotation

.ServletRequestMethodArgumentResolver

参数类型是以下任何一种

1. org.springframework.web.context.request.WebRequest及其子类

2. javax.servlet.ServletRequest及其子类

3. org.springframework.web.multipart.MultipartRequest及其子类

4. javax.servlet.http.HttpSession及其子类

5. javax.servlet.http.PushBuilder及其子类

6. java.security.Principal及其子类

7. java.io.InputStream及其子类

8. java.io.Reader及其子类

9. org.springframework.http.HttpMethod

10. java.util.Locale

11. java.util.TimeZone

12. java.time.ZoneId

 

org.springframework.web.servlet.mvc.method.annotation

.ServletResponseMethodArgumentResolver

参数类型是javax.servlet.ServletResponse及其子类或java.io.OutputStream及其子类或java.io.Writer及其子类

 

org.springframework.web.servlet.mvc.method.annotation

.HttpEntityMethodProcessor

参数类型是org.springframework.http.RequestEntity或者org.springframework.http.HttpEntity

 

org.springframework.web.servlet.mvc.method.annotation

.RedirectAttributesMethodArgumentResolver

参数类型是org.springframework.web.servlet.mvc.support.RedirectAttributes及其子类

 

org.springframework.web.method.annotation

.ModelMethodProcessor

参数类型是org.springframework.ui.Model及其子类型

 

org.springframework.web.method.annotation

.MapMethodProcessor

参数类型是Map及其子类型且参数上没有任何注解

 

org.springframework.web.method.annotation

.ErrorsMethodArgumentResolver

参数类型是org.springframework.validation.Errors及其子类

 

org.springframework.web.method.annotation

.SessionStatusMethodArgumentResolver

参数类型是org.springframework.web.bind.support.SessionStatus

 

org.springframework.web.servlet.mvc.method.annotation

.UriComponentsBuilderMethodArgumentResolver

参数类型是org.springframework.web.util.UriComponentsBuilder或者org.springframework.web.servlet.support.ServletUriComponentsBuilder

 

AbstractNamedValueMethodArgumentResolver

AbstractNamedValueMethodArgumentResolver是一个抽象类,它是name-value型参数解析器的父类。name-value型不太好解释,像Request parameters、request headers、path variables就是name-value的例子。大概就是每个参数有name标记参数的名字、required标记参数是否必须、default value标记默认值,根据name从请求中解析参数的值。

主要成员属性

  • configurableBeanFactory:Srping的BeanFactory,在这里用来处理字符串的占位符以及Spel表达式,因为参数的name支持占位符配置。

支持的参数条件

AbstractNamedValueMethodArgumentResolver是抽象类,支持的参数条件由其具体实现类指定

参数解析流程

AbstractNamedValueMethodArgumentResolver是抽象类,其控制name-value型参数解析的整体流程,有些细节或者数据获取需要各子类实现。name-value型参数解析器解析流程大致如下,需要子类实现的部分有备注:

1 获取NamedValueInfo信息namedValueInfo(name、required、default value)(由子类实现

2 解析namedValueInfo中name的占位符以及SPEL表达式

3 解析name对应的值value(由子类实现

4 如果value为null

    4.1 如果namedValueInfo默认值不为空则取默认值

    4.2 如果namedValueInfo默认值为空且namedValueInfo的isRequired为true执行value缺失逻辑-抛异常(vlaue确实逻辑可被子类覆盖)

    4.3 空值处理:如果是Boolean取Boolean.False,其他基本类型则抛异常,其他不处理

5 使用WebDataBinder对value进行转换使其符合要解析的参数类型

6 对value解析后处理:默认不处理(可由子类覆盖

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
... ...

    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        
        //笔者注:获取namedValueInfo信息,由子类实现
		NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
		MethodParameter nestedParameter = parameter.nestedIfOptional();
        
        //笔者注:对name进行占位符、spel表达式解析返回真正的name
		Object resolvedName = resolveStringValue(namedValueInfo.name);
		if (resolvedName == null) {
			throw new IllegalArgumentException(
					"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
		}

        //笔者注:解析name对应的value,由子类实现
		Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
		if (arg == null) {

            //笔者注: 如果没有解析出value,则进行默认值处理
			if (namedValueInfo.defaultValue != null) {
				arg = resolveStringValue(namedValueInfo.defaultValue);
			}
			else if (namedValueInfo.required && !nestedParameter.isOptional()) {
                
                // 笔者注: 参数必传,则执行value缺失逻辑-可由子类覆盖
				handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
			}
			arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
		}
		else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
			arg = resolveStringValue(namedValueInfo.defaultValue);
		}

        //笔者注: 使用DataBinder对value做类型转换,以符合参数的类型
		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());
			}
		}

        //笔者注:解析后处理,默认是不处理,可由子类覆盖
		handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

		return arg;
	}
... ...
}

下面介绍AbstractNamedValueMethodArgumentResolver的具体实现类,因为解析流程是遵守上面解析逻辑的,只有需要子类实现部分不同,所以只对子类实现部分进行介绍

RequestParamMethodArgumentResolver

主要成员变量

  • useDefaultResolution:bool类型,是否作为默认的参数解析器

支持的参数条件

参数符合以下任一条件

1. 被@RequestParam注解且参数类型不是Map

2. 被@RequestParam注解且参数类型是Map且@RequestParam注解的name属性不为空

3. 没有注解@RequestParam且没有注解@RequestPart且参数是MultipartFile或part(与multipart requests相关)

4. 如果解析器作为默认解析器即useDefaultResolution为true且参数类型是简单类型,其中简单类型包括:基本类型及其包装类型、Date、Number、Enum、CharSequence、URL、URI、Temporal、Locale、Class等

参数解析流程

同AbstractNamedValueMethodArgumentResolver。

a. 获取NamedValueInfo信息

返回RequestParamNamedValueInfo类型的对象,name、isRequired、defaultValue来自注解@RequestParam。如果没有@RequestParam注解则name为""、isRequired为false

b. 解析name对应的值value

1 如果参数类型是org.springframework.web.multipart.MultipartFile及其子类或者是MultipartFile类型的集合或数组,则从request解析MultipartFile对象

2 如果如果参数类型是javax.servlet.http.Part及其子类或者是Part类型的集合或数组,则从request解析Part对象

3 如果request是org.springframework.web.multipart.MultipartRequest,则取request第一个MultipartFile最为value

4 如果前面没有解析出value,则从request的parameterMap获取name对应的value

c. value缺失逻辑

根据参数类型不同抛不同类型的异常

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
... ...
    //笔者注:RequestParamMethodArgumentResolver重写父类方法,根据参数类型抛不同的异常
    protected void handleMissingValue(String name, MethodParameter parameter, NativeWebRequest request)
			throws Exception {

		HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
		if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
			if (servletRequest == null || !MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
				throw new MultipartException("Current request is not a multipart request");
			}
			else {
				throw new MissingServletRequestPartException(name);
			}
		}
		else {
			throw new MissingServletRequestParameterException(name,
					parameter.getNestedParameterType().getSimpleName());
		}
	}
... ...
}

d. value解析后处理

RequestParamMethodArgumentResolver没有重写父类方法AbstractNamedValueMethodArgumentResolver#handleResolvedValue,保持父类逻辑即不处理

PathVariableMethodArgumentResolver

主要成员变量

支持的参数条件

该解析支持符合以下条件任一条件的参数

1. 参数包含注解@PathVariable且参数类型不是Map及其子类

2. 参数包含注解@PathVariable且参数类型是Map及其子类且注解@PathVariable的value属性不为空

参数解析流程

同AbstractNamedValueMethodArgumentResolver。

a. 获取NamedValueInfo信息

返回PathVariableNamedValueInfo类型对象,name、isRequired、defaultValue来自参数上的注解@PathVariable。

b. 解析name对应的值value

1 从request取出属性"org.springframework.web.servlet.HandlerMapping.uriTemplateVariables"。(该属性是在RequestMappingHandlerMapping匹配Handler阶段解析出uriTemplateVariables并且放在request中)

2 从uriTemplateVariables取得name对应value

c. value缺失逻辑

重写了父类方法,抛出异常org.springframework.web.bind.MissingPathVariableException

d. value解析后处理

PathVariableMethodArgumentResolver重写了父类方法AbstractNamedValueMethodArgumentResolver#handleResolvedValue。

将解析出来的name、value对放到request属性("org.springframework.web.servlet.View.pathVariables")中

public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
... ...
    //笔者注:重写了父类方法,将解析出来name-value添加到request的属性中
    protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter,
			@Nullable ModelAndViewContainer mavContainer, NativeWebRequest request) {

		String key = View.PATH_VARIABLES;
		int scope = RequestAttributes.SCOPE_REQUEST;
		Map<String, Object> pathVars = (Map<String, Object>) request.getAttribute(key, scope);
		if (pathVars == null) {
			pathVars = new HashMap<>();
			request.setAttribute(key, pathVars, scope);
		}
        //笔者注:将解析出来name-value添加到request的属性中
		pathVars.put(name, arg);
	}
... ...
}

MatrixVariableMethodArgumentResolver

主要成员变量

支持的参数条件

该解析支持符合以下条件任一条件的参数

1. 参数包含注解@MatrixVariable且参数类型不是Map及其子类

2. 参数包含注解@MatrixVariable且参数类型是Map及其子类且注解@MatrixVariable的value属性不为空

参数解析流程

同AbstractNamedValueMethodArgumentResolver。

a. 获取NamedValueInfo信息

返回MatrixVariableNamedValueInfo类型对象,name、isRequired、defaultValue来自注解@MatrixVariable。

b. 解析name对应的值value

1 从request取出属性"org.springframework.web.servlet.HandlerMapping.matrixVariables",类型是Map<String, MultiValueMap<String, String>>。(该属性在RequestMappingHandlerMapping匹配Handler阶段解析出MatrixVariable并且放在request中)

2 如果@MatrixVariable指定了pathVar则从matrixVariables取pathVar对应的集合并从其中获取name对应的值,然后返回,否则进入3

3 依次遍历matrixVariables元素,从元素(MultiValueMap)中获取name对应的值,如果在多个元素中找到name则抛异常

c. value缺失逻辑

抛出异常org.springframework.web.bind.MissingMatrixVariableException

d. value解析后处理

未重写父类逻辑即不处理

RequestHeaderMethodArgumentResolver

主要成员变量

支持的参数条件

 参数包含注解@RequestHeader且参数类型不是Map及其子类

参数解析流程

同AbstractNamedValueMethodArgumentResolver。

a. 获取NamedValueInfo信息

返回RequestHeaderNamedValueInfo类型对象,name、isRequired、defaultValue来自注解@RequestHeader。

b. 解析name对应的值value

从request headers中取出name对应的values

c. value缺失逻辑

抛出异常org.springframework.web.bind.MissingRequestHeaderException

d. value解析后处理

未重写父类逻辑

 

ServletCookieValueMethodArgumentResolver

主要成员变量

  • urlPathHelper:org.springframework.web.util.UrlPathHelper类型组件,对cookievalue做解码

支持的参数条件

参数包含注解@CookieValue

参数解析流程

同AbstractNamedValueMethodArgumentResolver。

a. 获取NamedValueInfo信息

返回CookieValueNamedValueInfo类型对象,name、isRequired、defaultValue来自注解@CookieValue。

b. 解析name对应的值value

1 从request cookies中取出name对应的Cookie

2 如果参数类型是Cookie则直接返回,否则返回Cookie的value

c. value缺失逻辑

抛出异常org.springframework.web.bind.MissingRequestCookieException

d. value解析后处理

未重写父类逻辑

ExpressionValueMethodArgumentResolver

主要成员变量

支持的参数条件

参数包含注解@Value

参数解析流程

同AbstractNamedValueMethodArgumentResolver。

a. 获取NamedValueInfo信息

返回ExpressionValueNamedValueInfo类型对象,name、isRequired、defaultValue来自注解@Value。

b. 解析name对应的值value

直接返回null。也就是说会走到默认值流程,即配置@Value时的value。如果value有placeholder,系统在启动的时候Spring会解析替换placeholder

public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
... ...
    //笔者注:直接返回null,就是要走默认值流程,即@Value配置的placeholder解析出来的值
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
		// No name to resolve
		return null;
	}
... ...
}

c. value缺失逻辑

抛出异常java.lang.UnsupportedOperationException

d. value解析后处理

未重写父类逻辑

SessionAttributeMethodArgumentResolver

主要成员变量

支持的参数条件

参数包含注解@SessionAttribute

参数解析流程

同AbstractNamedValueMethodArgumentResolver。

a. 获取NamedValueInfo信息

返回NamedValueInfo类型对象,name、isRequired、defaultValue来自注解@SessionAttribute。

b. 解析name对应的值value

从requst中取出name对应的SCOPE_SESSION作用域的属性

c. value缺失逻辑

抛出异常org.springframework.web.bind.ServletRequestBindingException

d. value解析后处理

未重写父类逻辑

RequestAttributeMethodArgumentResolver

主要成员变量

支持的参数条件

参数包含注解@RequestAttribute

参数解析流程

同AbstractNamedValueMethodArgumentResolver。

a. 获取NamedValueInfo信息

返回NamedValueInfo类型对象,name、isRequired、defaultValue来自注解@RequestAttribute。

b. 解析name对应的值value

从request中取出name对应的SCOPE_REQUEST作用域的属性

c. value缺失逻辑

抛出异常org.springframework.web.bind.ServletRequestBindingException

d. value解析后处理

未重写父类逻辑

RequestParamMapMethodArgumentResolver

主要成员变量

支持的参数条件

参数包含注解@RequestParam且类型是Map及其子类且注解@RequestParam属性的name为空

参数解析流程

1 如果参数类型是org.springframework.util.MultiValueMap子类,则

    1.1 如果元素的类型是org.springframework.web.multipart.MultipartFile则从request中读取multiFileMap返回

    1.2 如果元素的类型是javax.servlet.http.Part则从request读取parts对象,组建org.springframework.util.LinkedMultiValueMap类型对象返回

    1.3 从request读取parameterMap,组建org.springframework.util.LinkedMultiValueMap类型对象返回

2 如果参数类型是Map及其子类

    2.1 如果元素的类型是org.springframework.web.multipart.MultipartFile则从request中读取multiFileMap返回

    2.2 如果元素的类型是javax.servlet.http.Part则从request读取parts对象,组建org.springframework.util.LinkedHashMap类型对象返回

    2.3 从request读取parameterMap,组建org.springframework.util.LinkedHashMap类型对象返回

PathVariableMapMethodArgumentResolver

主要成员变量

支持的参数条件

参数包含注解@PathVariable且类型是Map及其子类且注解@PathVariable属性的name为空

参数解析流程

从request取出属性"org.springframework.web.servlet.HandlerMapping.uriTemplateVariables"。(该属性是在RequestMappingHandlerMapping匹配Handler阶段解析出uriTemplateVariables并且放在request中)

MatrixVariableMapMethodArgumentResolver

主要成员变量

支持的参数条件

参数包含注解@MatrixVariable且类型是Map及其子类且注解@MatrixVariable属性的name为空

参数解析流程

1 从request取出属性"org.springframework.web.servlet.HandlerMapping.matrixVariables",类型是Map<String, MultiValueMap<String, String>>。(该属性在RequestMappingHandlerMapping匹配Handler阶段解析出MatrixVariable并且放在request中)

2 如果@MatrixVariable指定了pathVar则从matrixVariables取对应的值并加入到org.springframework.util.LinkedMultiValueMap对象,然后返回,否则进入3

3 依次遍历matrixVariables元素加入到org.springframework.util.LinkedMultiValueMap对象,并返回

 

AbstractMessageConverterMethodArgumentResolver

AbstractMessageConverterMethodArgumentResolver是一个抽象类,它提供了一些工具方法从request body读取对象。

主要成员变量

  • messageConverters:元素类型是HttpMessageConverter的列表,HttpMessageConverter用于从body中读取出给定类型的对象或将给定对象写到body
  • allSupportedMediaTypes:所有支持的media
  • advice:RequestResponseBodyAdviceChain类型,ResponseBodyAdvice和RequestBodyAdvice类型对象的链表,读取和写入body前或后执行一些逻辑

readWithMessageConverters

1 读取request的请求头"Content-Type"

2 遍历messageConverters,如果找到能支持参数实际类型转换的元素,进入3,否则跳到4

3 如果有request body,则

    3.1 执行RequestBodyAdvice中读取request body前处理(RequestResponseBodyAdviceChain#beforeBodyRead)

    3.2 使用HttpMessageConverter读取并转换request body

    3.3 执行RequestBodyAdvice中读取request body后处理(RequestResponseBodyAdviceChain#afterBodyRead)

4 如果没有request body 则

    4.1 执行RequestBodyAdvice中关于空body的处理(RequestResponseBodyAdviceChain#handleEmptyBody)

5 如果读取到对象则返回该对象,否则抛异常HttpMediaTypeNotSupportedException

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
    ... ...

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

		MediaType contentType;
		boolean noContentType = false;
		try {
//笔者注:读取Content-Type
			contentType = inputMessage.getHeaders().getContentType();
		}
		catch (InvalidMediaTypeException ex) {
			throw new HttpMediaTypeNotSupportedException(ex.getMessage());
		}
		if (contentType == null) {
			noContentType = true;
			contentType = MediaType.APPLICATION_OCTET_STREAM;
		}

		Class<?> contextClass = parameter.getContainingClass();
		Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
		if (targetClass == null) {
			ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
			targetClass = (Class<T>) resolvableType.resolve();
		}

		HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
		Object body = NO_VALUE;
        
		EmptyBodyCheckingHttpInputMessage message;
		try {
			message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
            
            //笔者注:遍历messageConverters
			for (HttpMessageConverter<?> converter : this.messageConverters) {
				Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
				GenericHttpMessageConverter<?> genericConverter =
						(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
				if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
						(targetClass != null && converter.canRead(targetClass, contentType))) {
					if (message.hasBody()) {
                        
                        //笔者注:读取body之前执行RequstbodyAdvice的beforeBodyRead
						HttpInputMessage msgToUse =
								getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
						body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
								((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
                        //笔者注:读取body之后执行RequstbodyAdvice的afterBodyRead
						body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
					}
					else {
                        //笔者注:没有request body则执行RequstbodyAdvice的handleEmptyBody
						body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
					}
					break;
				}
			}
		}
		catch (IOException ex) {
			throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
		}

        //笔者注:没有读取到对象,根据情况抛异常HttpMediaTypeNotSupportedException
		if (body == NO_VALUE) {
			if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
					(noContentType && !message.hasBody())) {
				return null;
			}
			throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
		}

		MediaType selectedContentType = contentType;
		Object theBody = body;
		LogFormatUtils.traceDebug(logger, traceOn -> {
			String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
			return "Read \"" + selectedContentType + "\" to [" + formatted + "]";
		});

		return body;
	}

    ... ...
}

 

RequestResponseBodyMethodProcessor

主要成员变量

支持的参数条件

参数包含注解@RequestBody

参数解析流程

1. 从request的body中读取出对应类型的对象,参考AbstractMessageConverterMethodArgumentResolver

2. 对对象进行valid验证

3. 如果验证有错误且当前解析的参数后一个参数类型不是org.springframework.validation.Errors,则抛异常MethodArgumentNotValidException并结束解析流程,否则进入4

4. 将绑定结果添加到mavContainer属性中,属性名以"org.springframework.validation.BindingResult."开头

5. 返回对象

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
... ...
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		parameter = parameter.nestedIfOptional();
        //笔者注:AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters读取参数类型的对象
		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
		String name = Conventions.getVariableNameForParameter(parameter);

		if (binderFactory != null) {
			WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
			if (arg != null) {
   
                //笔者注:数据检查
				validateIfApplicable(binder, parameter);
                //笔者注:绑定有错误且下一个参数不是Errors类型则抛异常
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
					throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
				}
			}
			if (mavContainer != null) {
				mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
			}
		}

        //笔者注:返回绑定后对象
		return adaptArgumentIfNecessary(arg, parameter);
	}
    ... ...
}

HttpEntityMethodProcessor

主要成员变量

支持的参数条件

参数类型是org.springframework.http.RequestEntity或者org.springframework.http.HttpEntity

参数解析流程

1 获取参数的实际类型(HttpEntity或RequestEntity泛型)

2 从request body中读取对象,参考AbstractMessageConverterMethodArgumentResolver

3 根据参数的类型创建RequestEntity或HttpEntity对象

public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor {
... ...
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)
			throws IOException, HttpMediaTypeNotSupportedException {

		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		Type paramType = getHttpEntityType(parameter);
		if (paramType == null) {
			throw new IllegalArgumentException("HttpEntity parameter '" + parameter.getParameterName() +
					"' in method " + parameter.getMethod() + " is not parameterized");
		}

        //笔者注:AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters从request body中读取对象
		Object body = readWithMessageConverters(webRequest, parameter, paramType);
		if (RequestEntity.class == parameter.getParameterType()) {
			return new RequestEntity<>(body, inputMessage.getHeaders(),
					inputMessage.getMethod(), inputMessage.getURI());
		}
		else {
			return new HttpEntity<>(body, inputMessage.getHeaders());
		}
	}
    ... ...
}

RequestPartMethodArgumentResolver

主要成员变量

支持的参数条件

参数符合以下任一条件

1. 参数包含注解@RequestPart

2. 参数不包含注解@RequestParam且参数类型org.springframework.web.multipart.MultipartFile及其子类或javax.servlet.http.Part及其子类

参数解析流程

1. 将request转为org.springframework.web.multipart.MultipartHttpServletRequest类型的对象,从其中读取MultipartFile或者Part元素。如果读取到则返回,否则进入2

2. 从request body中读取对象,参考AbstractMessageConverterMethodArgumentResolver

 

RequestHeaderMapMethodArgumentResolver

主要成员变量

支持的参数条件

参数包含注解@RequestHeader且类型是Map及其子类

参数解析流程

1 如果参数类型是HttpHeaders及其子类,创建HttpHeaders对象并从request header中取得所有header填充进去,返回HttpHeaders对象。否则进入2

2 如果参数类型是org.springframework.util.MultiValueMap及其子类,创建org.springframework.util.LinkedMultiValueMap对象并从request header中取得所有header填充进去,返回LinkedMultiValueMap对象。否则进入3

3 创建java.util.LinkedHashMap对象并从request header中取得所有header填充进去,返回LinkedHashMap对象

 

ServletRequestMethodArgumentResolver

主要成员变量

支持的参数条件

参数类型是以下任何一种

1. org.springframework.web.context.request.WebRequest及其子类

2. javax.servlet.ServletRequest及其子类

3. org.springframework.web.multipart.MultipartRequest及其子类

4. javax.servlet.http.HttpSession及其子类

5. javax.servlet.http.PushBuilder及其子类

6. java.security.Principal及其子类

7. java.io.InputStream及其子类

8. java.io.Reader及其子类

9. org.springframework.http.HttpMethod

10. java.util.Locale

11. java.util.TimeZone

12. java.time.ZoneId

参数解析流程

1 如果参数类型是org.springframework.web.context.request.WebRequest及其子类、javax.servlet.ServletRequest及其子类或org.springframework.web.multipart.MultipartRequest及其子类,则将request转换得到对应的类型对象并返回

2 如果参数类型是javax.servlet.http.HttpSession及其子类则返回javax.servlet.http.HttpServletRequest#getSession()

3 如果参数类型是javax.servlet.http.PushBuilder及其子类则返回javax.servlet.http.HttpServletRequest#newPushBuilder

4 如果参数类型是java.io.InputStream及其子类则返回javax.servlet.ServletRequest#getInputStream

5 如果参数类型是java.io.Reader及其子类则返回javax.servlet.ServletRequest#getReader

6 如果参数类型是java.security.Principal及其子类则返回javax.servlet.http.HttpServletRequest#getUserPrincipal

7 解析并返回javax.servlet.http.HttpServletRequest#getMethod

8如果参数类型是java.util.Locale则使用工具方法org.springframework.web.servlet.support.RequestContextUtils#getLocale从request中解析并返回

9 如果参数类型是java.util.TimeZone则使用工具方法org.springframework.web.servlet.support.RequestContextUtils#getTimeZone从request中解析并返回

10 如果参数类型是java.time.ZoneId则使用工具方法org.springframework.web.servlet.support.RequestContextUtils#getTimeZone从request中解析并返回

ServletResponseMethodArgumentResolver

主要成员变量

支持的参数条件

参数类型是javax.servlet.ServletResponse及其子类或java.io.OutputStream及其子类或java.io.Writer及其子类

参数解析流程

1 如果参数类型是javax.servlet.ServletResponse则返回response对象,否则进入2

2 如果参数类型是java.io.OutputStream则返回javax.servlet.ServletResponse#getOutputStream,否则进入3

3 如果参数类型是java.io.Writer则返回javax.servlet.ServletResponse#getWriter,否则抛异常

RedirectAttributesMethodArgumentResolver

主要成员变量

支持的参数条件

参数类型是org.springframework.web.servlet.mvc.support.RedirectAttributes及其子类

参数解析流程

创建一个org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap对象返回

ModelMethodProcessor

主要成员变量

支持的参数条件

参数类型是org.springframework.ui.Model及其子类型

参数解析流程

直接从mavContainer取ModelMap并返回

MapMethodProcessor

主要成员变量

支持的参数条件

参数类型是Map及其子类型且参数上没有任何注解

参数解析流程

直接从mavContainer取ModelMap并返回

UriComponentsBuilderMethodArgumentResolver

支持的参数条件

参数类型是org.springframework.web.util.UriComponentsBuilder或者org.springframework.web.servlet.support.ServletUriComponentsBuilder

参数解析流程

根据request创建ServletUriComponentsBuilder对象,ServletUriComponentsBuilder的scheme、host、port从request设置,path从contextpath和servletpath拼接。

public class UriComponentsBuilderMethodArgumentResolver implements HandlerMethodArgumentResolver {


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

		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
		Assert.state(request != null, "No HttpServletRequest");
		return ServletUriComponentsBuilder.fromServletMapping(request);
	}

}

 

SessionStatusMethodArgumentResolver

支撑的参数条件

参数类型是org.springframework.web.bind.support.SessionStatus

参数解析流程

直接读取mavContainer的属性sessionStatus即ModelAndViewContainer#getSessionStatus

ErrorsMethodArgumentResolver

支持的参数条件

参数类型是org.springframework.validation.Errors及其子类

参数解析流程

model中最后一个元素且该元素的key是以"org.springframework.validation.BindingResult."开头,否则抛异常。所以Errors类型参数必须紧跟着@ModuleAttribute、@RequestBody或@RequestPart后声明,否则modelMap中最后一个元素不满足条件。

ServletModelAttributeMethodProcessor

支持的参数条件

参数符合以下任一条件

1. 参数有注解@ModuleAttribute

2. 属性annotationNotRequired为true且参数不是简单类型,简单类型包括

参数解析流程

ServletModelAttributeMethodProcessor是ModelAttributeMethodProcessor子类,解析的方法在ModelAttributeMethodProcessor#resolveArgument

1 根据注解@ModuleAttribute获取参数name(a. 注解中指定了name b. 根据类名生成)

2 如果mavContainer中已经有该name对应的对象则跳到4,否则进去3创建对象

3 创建对象obj

    3.1 如果request包含该name的请求参数或者路径变量且能被转换为对应类型则返回转换后对象,否则进入3.2

    3.2 获取类型的构造方法,如果构造方法没有参数,创建对象返回,否则进入3.3

    3.3 取得构造方法的参数并分析参数的name(来源于注解@java.beans.ConstructorProperties或ParameterNameDiscoverer#getParameterNames(java.lang.reflect.Constructor<?>))

    3.4 从request中取得name对应值转换为构造方法的参数类型,使用构造方法创建对象返回

4 从request获取参数绑定到对象obj中的属性:WebRequestDataBinder#bind

5 返回绑定后的obj



上一篇 RequestMappingHandlerAdapter

下一篇 ModelAttribute使用方法

再下一篇 返回处理器HandlerMethodReturnValueHandler

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值