Spring 源码学习(十四)—— HandlerMethodArgumentResolver

HandlerMethodArgumentResolver 对象用于向外提供处理器方法参数解析,其提供了 supportsParameter 方法与 resolveArgument 两个方法,分别用于判断参数的支持度与方法参数的解析;

java 复制代码
public interface HandlerMethodArgumentResolver {

	boolean supportsParameter(MethodParameter parameter);

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

}

HandlerMethodArgumentResolver 接口拥有许多实现,本文不会全部介绍,只会挑选其中重要的实现进行介绍。

1. HandlerMethodArgumentResolverComposite

1.1 属性

HandlerMethodArgumentResolverComposite 类用于将多个 HandlerMethodArgumentResolver 组合到一起使用,其拥有两个属性,一个用于保存所有的 HandlerMethodArgumentResolver 对象组合,另一个则是参数解析器缓存。

java 复制代码
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

	private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();

	private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
			new ConcurrentHashMap<>(256);

	public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver resolver) {
		this.argumentResolvers.add(resolver);
		return this;
	}

	public HandlerMethodArgumentResolverComposite addResolvers(
			@Nullable HandlerMethodArgumentResolver... resolvers) {

		if (resolvers != null) {
			Collections.addAll(this.argumentResolvers, resolvers);
		}
		return this;
	}

	public HandlerMethodArgumentResolverComposite addResolvers(
			@Nullable List<? extends HandlerMethodArgumentResolver> resolvers) {

		if (resolvers != null) {
			this.argumentResolvers.addAll(resolvers);
		}
		return this;
	}

	public List<HandlerMethodArgumentResolver> getResolvers() {
		return Collections.unmodifiableList(this.argumentResolvers);
	}

	public void clear() {
		this.argumentResolvers.clear();
	}
}

1.2 方法

HandlerMethodArgumentResolverComposite 的 supportsParameter 与 resolveArgument 方法实现都是通过 getArgumentResolver 方法获取对应解析器,然后在执行对应动作;

java 复制代码
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

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

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

		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);
	}
}

1.2.1 getArgumentResolver 方法

getArgumentResolver 方法则首先从 argumentResolverCache 中获取对应解析器,没获取到才会遍历 argumentResolvers 参数,通过 supportsParameter 方法获取对应解析器,保存至 argumentResolvers 缓存并返回。

java 复制代码
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

	@Nullable
	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}
}

2. RequestResponseBodyMethodProcessor

RequestResponseBodyMethodProcessor 类拥有两个功能,一个是对 RequestBody 请求参数进行解析,另一个则是处理 ResponseBody 响应结果;由于本文只是针对 HandlerMethodArgumentResolver 方法参数处理器的实现进行分析,因此只会对请求参数解析流程进行分析,对应返参处理流程的分析(AbstractMessageConverterMethodProcessor 中定义的方法及 handleReturnValue 相关方法)将会在后续 HandlerMethodReturnValueHandler 返回值处理器接口及其实现中进行;

2.0 流程概览

2.1 AbstractMessageConverterMethodArgumentResolver 抽象类

AbstractMessageConverterMethodArgumentResolver 类为将请求体解析为方法的基类;其只提供了一些请求体交互的方法而未提供任何 HandlerMethodArgumentResolver 接口方法的实现。

2.1.1 属性

常量

AbstractMessageConverterMethodArgumentResolver 类拥有两个常量,其一是 SUPPORTED_METHODS 所支持的方法,包含 POST、PUT 以及 PATCH,另一个则是用于标识请求体无任何内容的 NO_VALUE。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {

	private static final Set<HttpMethod> SUPPORTED_METHODS =
			EnumSet.of(HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH);

	private static final Object NO_VALUE = new Object();
}
类变量

AbstractMessageConverterMethodArgumentResolver 拥有三个变量,分别为可用的 http 消息转换器列表 messageConverters 用于提取请求体内容,支持的媒体类型列表 allSupportedMediaTypes 及请求响应体处理器切面链 advice。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {

	protected final List<HttpMessageConverter<?>> messageConverters;

	protected final List<MediaType> allSupportedMediaTypes;

	private final RequestResponseBodyAdviceChain advice;

	RequestResponseBodyAdviceChain getAdvice() {
		return this.advice;
	}
}

2.1.2 方法

构造方法

创建 AbstractMessageConverterMethodArgumentResolver 对象需要两个参数 converters 消息转换器列表与请求响应体切面处理器列表 requestResponseBodyAdvice,其中 converters 是必须的,其除了用于直接为 messageConverters 属性赋值外,还未调用 getAllSupportedMediaTypes 方法获取其所能解析的所有媒体列表并保存到 allSupportedMediaTypes 属性之中,而 requestResponseBodyAdvice 在使用 RequestResponseBodyAdviceChain 封装后保存至 advice 属性之中。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {

	public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters) {
		this(converters, null);
	}

	public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters,
			@Nullable List<Object> requestResponseBodyAdvice) {

		Assert.notEmpty(converters, "'messageConverters' must not be empty");
		this.messageConverters = converters;
		this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters);
		this.advice = new RequestResponseBodyAdviceChain(requestResponseBodyAdvice);
	}
}

getAllSupportedMediaTypes 方法依次获取 messageConverters 列表中所有对应的 MediaType 媒体类型,在去重、排序后返回。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {

	private static List<MediaType> getAllSupportedMediaTypes(List<HttpMessageConverter<?>> messageConverters) {
		Set<MediaType> allSupportedMediaTypes = new LinkedHashSet<>();
		for (HttpMessageConverter<?> messageConverter : messageConverters) {
			allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
		}
		List<MediaType> result = new ArrayList<>(allSupportedMediaTypes);
		MediaType.sortBySpecificity(result);
		return Collections.unmodifiableList(result);
	}
}
readWithMessageConverters 方法

readWithMessageConverters 方法为 AbstractMessageConverterMethodArgumentResolver 类的核心方法,其提供了核心功能,即将请求体读取为指定对象并返回,其拥有两个不同的重载,一个是从 NativeWebRequest 类型的请求体中读取数据,另一个则是从 HttpInputMessage 中解析对象。

从 NativeWebRequest 类型的请求体中读取数据首先调用 createInputMessage 方法使用 NativeWebRequest 构建 HttpInputMessage 对象,并调用另一个 readWithMessageConverters 方法继续读取并返回;

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
	@Nullable
	protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
			Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

		HttpInputMessage inputMessage = createInputMessage(webRequest);
		return readWithMessageConverters(inputMessage, parameter, paramType);
	}
}

readWithMessageConverters 方法首先获取 inputMessage 请求的内容类型,若未设置,则会赋值为 APPLICATION_OCTET_STREAM;随后获取 parameter 参数的上下文类型 Class 对象及本身对象类型类对象;随后选取支持类型与媒体类型的消息转换器,在 message 拥有请求体是,依次使用切面的 beforeBodyRead 进行切面前置处理,消息转换器的 read 方法获取对象及切面的 afterBodyRead 方法进行后处理并将最终结果保存到 body 变量之中,在 message 没有请求体时,直接调用切面的 handleEmptyBody 方法进行处理空请求体并将其结果保存至 body 变量之中,最后若 body 不为 NO_VALUE 直接返回该变量值,否则在 httpMethod 为空、httpMethod 不在 SUPPORTED_METHODS 中或满足没有请求体的同时没有媒体类型标识时直接返回 null,不满足上述所有条件则会直接抛出异常。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
	@Nullable
	protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
			Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

		MediaType contentType;
		boolean noContentType = false;
		try {
			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);

			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()) {
						HttpInputMessage msgToUse =
								getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
						body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
								((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
						body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
					}
					else {
						body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
					}
					break;
				}
			}
		}
		catch (IOException ex) {
			throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
		}

		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;
	}
}
createInputMessage 方法

createInputMessage 方法在 webRequest 为 HttpServletRequest 对象时直接使用 ServletServerHttpRequest 对其进行封装并返回,否则抛出异常。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
	protected ServletServerHttpRequest createInputMessage(NativeWebRequest webRequest) {
		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
		Assert.state(servletRequest != null, "No HttpServletRequest");
		return new ServletServerHttpRequest(servletRequest);
	}
}
validateIfApplicable 方法

validateIfApplicable 方法用于方法参数的验证,通过参数的 Validated 注解或名为 Valid 开头注解对象的 value 属性值与 binder 参数的 validate 方法来进行验证。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
	protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
		Annotation[] annotations = parameter.getParameterAnnotations();
		for (Annotation ann : annotations) {
			Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
			if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
				Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
				Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
				binder.validate(validationHints);
				break;
			}
		}
	}
}
isBindExceptionRequired 方法

isBindExceptionRequired 方法用于判断当前参数是否没有指定的绑定异常;其是通过判断当前参数的后续参数是否不为 Error 的子类进行判断的。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
	protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
		int i = parameter.getParameterIndex();
		Class<?>[] paramTypes = parameter.getExecutable().getParameterTypes();
		boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
		return !hasBindingResult;
	}
}
adaptArgumentIfNecessary 方法

adaptArgumentIfNecessary 方法用于适配 Optional 类型参数。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
	@Nullable
	protected Object adaptArgumentIfNecessary(@Nullable Object arg, MethodParameter parameter) {
		if (parameter.getParameterType() == Optional.class) {
			if (arg == null || (arg instanceof Collection && ((Collection<?>) arg).isEmpty()) ||
					(arg instanceof Object[] && ((Object[]) arg).length == 0)) {
				return Optional.empty();
			}
			else {
				return Optional.of(arg);
			}
		}
		return arg;
	}
}

2.1.3 内部类

EmptyBodyCheckingHttpInputMessage 类

EmptyBodyCheckingHttpInputMessage 类为 HttpInputMessage 实现类,其用于封装指定 inputMessage,扩展了空请求体检验功能。

java 复制代码
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
	private static class EmptyBodyCheckingHttpInputMessage implements HttpInputMessage {

		private final HttpHeaders headers;

		@Nullable
		private final InputStream body;

		public EmptyBodyCheckingHttpInputMessage(HttpInputMessage inputMessage) throws IOException {
			this.headers = inputMessage.getHeaders();
			InputStream inputStream = inputMessage.getBody();
			if (inputStream.markSupported()) {
				inputStream.mark(1);
				this.body = (inputStream.read() != -1 ? inputStream : null);
				inputStream.reset();
			}
			else {
				PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
				int b = pushbackInputStream.read();
				if (b == -1) {
					this.body = null;
				}
				else {
					this.body = pushbackInputStream;
					pushbackInputStream.unread(b);
				}
			}
		}

		@Override
		public HttpHeaders getHeaders() {
			return this.headers;
		}

		@Override
		public InputStream getBody() {
			return (this.body != null ? this.body : StreamUtils.emptyInput());
		}

		public boolean hasBody() {
			return (this.body != null);
		}
	}
}

2.2 resolveArgument 方法

resolveArgument 方法首先通过 readWithMessageConverters 方法解析 webRequest 请求体并将解析结果保存到 arg 变量中并使用 Conventions 的 getVariableNameForParameter 生成参数对应的对象名;在 binderFactory 不为空时首先调用其 createBinder 方法创建对应数据绑定器,之后若 arg 解析参数不为空,依次调用 validateIfApplicable 与 isBindExceptionRequired 方法进行参数的验证,判断是否直接抛出异常,随后在 mavContainer 参数不为空时,直接将参数结果保存绑定到其 BindingResult.MODEL_KEY_PREFIX + name 属性上,最后调用 adaptArgumentIfNecessary 参数适配 Optional 参数。

java 复制代码
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
	@Override
	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		parameter = parameter.nestedIfOptional();
		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);
				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);
	}
}

2.3 readWithMessageConverters 方法

RequestResponseBodyMethodProcessor 类除了实现了 resolveArgument 方法时,还重写了 AbstractMessageConverterMethodArgumentResolver 抽象类的 readWithMessageConverters 方法用于支持参数的必填验证,参数的必填验证时通过 checkRequired 方法进行的,checkRequired 方法直接返回参数 RequestBody 注解的 required 方法值且是否不为 Optional 对象。

java 复制代码
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
	@Override
	protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
			Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
		Assert.state(servletRequest != null, "No HttpServletRequest");
		ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);

		Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
		if (arg == null && checkRequired(parameter)) {
			throw new HttpMessageNotReadableException("Required request body is missing: " +
					parameter.getExecutable().toGenericString(), inputMessage);
		}
		return arg;
	}

	protected boolean checkRequired(MethodParameter parameter) {
		RequestBody requestBody = parameter.getParameterAnnotation(RequestBody.class);
		return (requestBody != null && requestBody.required() && !parameter.isOptional());
	}
}

3. AbstractNamedValueMethodArgumentResolver 抽象类

AbstractNamedValueMethodArgumentResolver 为所有从各种"命名值"(named values)中解析控制器方法的参数值解析器通用父类;

3.0 流程概览

3.1 属性

java 复制代码
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {

	@Nullable
	private final ConfigurableBeanFactory configurableBeanFactory;

	@Nullable
	private final BeanExpressionContext expressionContext;

	private final Map<MethodParameter, NamedValueInfo> namedValueInfoCache = new ConcurrentHashMap<>(256);
}

AbstractNamedValueMethodArgumentResolver 类有三个属性,分别为 configurableBeanFactory 对象工厂、对象表达式上下文 expressionContext 及 namedValueInfoCache 命名值缓存。

3.2 方法

3.2.1 构造方法

java 复制代码
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
	public AbstractNamedValueMethodArgumentResolver() {
		this.configurableBeanFactory = null;
		this.expressionContext = null;
	}

	public AbstractNamedValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
		this.configurableBeanFactory = beanFactory;
		this.expressionContext =
				(beanFactory != null ? new BeanExpressionContext(beanFactory, new RequestScope()) : null);
	}
}

AbstractNamedValueMethodArgumentResolver 抽象类拥有 2 个构造方法,无参构造方法将属性置为 null,传入 beanFactory 对象工厂的构造方法在为 configurableBeanFactory 参数赋值的同时使用对象工厂构建 BeanExpressionContext 表达式上下文对象用于初始化 expressionContext 属性。

3.2.2 resolveArgument 方法

resolveArgument 方法首先调用 getNamedValueInfo 方法获取对应的 NamedValueInfo 对象,随后调用 parameter 参数的 nestedIfOptional 方法获取实际参数对象;并在之后调用 resolveEmbeddedValuesAndExpressions 方法解析参数名中占位符以及表达式,随后调用 resolveName 从指定位置处获取解析得到对应参数值并保存到 arg 变量之中,在未解析获取到任何值时且参数为必须时,直接调用 handleMissingValue 方法处理未查到参数异常,在其为空或空字符串且拥有默认值时,调用 resolveEmbeddedValuesAndExpressions 方法对默认值进行解析并更新到 arg 属性之中,否则在 arg 为 null 时调用 handleNullValue 方法对空参数值进行处理;随后使用 binderFactory 数据绑定工厂创建 WebDataBinder 数据绑定器对象并调用其 convertIfNecessary 方法将 arg 参数值转换为对应类型数据,最后调用 handleResolvedValue 方法进一步处理完成解析的参数并返回。

java 复制代码
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
	@Override
	@Nullable
	public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
		MethodParameter nestedParameter = parameter.nestedIfOptional();

		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 = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
			}
			else if (namedValueInfo.required && !nestedParameter.isOptional()) {
				handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
			}
			arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
		}
		else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
			arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
		}

		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;
	}

	@Nullable
	protected abstract Object resolveName(String name, MethodParameter parameter, NativeWebRequest request)
			throws Exception;

	@Nullable
	private Object handleNullValue(String name, @Nullable Object value, Class<?> paramType) {
		if (value == null) {
			if (Boolean.TYPE.equals(paramType)) {
				return Boolean.FALSE;
			}
			else if (paramType.isPrimitive()) {
				throw new IllegalStateException("Optional " + paramType.getSimpleName() + " parameter '" + name +
						"' is present but cannot be translated into a null value due to being declared as a " +
						"primitive type. Consider declaring it as object wrapper for the corresponding primitive type.");
			}
		}
		return value;
	}

	protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter,
			@Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
	}
}

getNamedValueInfo 方法首先尝试从 namedValueInfoCache 缓存中获取 NamedValueInfo 对象,在其不为空时直接返回;为空则会依次调用 createNamedValueInfo 方法创建并更新 NamedValueInfo 对象值,并保存至 namedValueInfoCache 缓存后返回。

java 复制代码
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
	private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
		NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
		if (namedValueInfo == null) {
			namedValueInfo = createNamedValueInfo(parameter);
			namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
			this.namedValueInfoCache.put(parameter, namedValueInfo);
		}
		return namedValueInfo;
	}

	protected abstract NamedValueInfo createNamedValueInfo(MethodParameter parameter);
}

updateNamedValueInfo 方法主要目的是在 info 没有对应名称时将其更新为方法名,在其不存在默认值时将其默认值更新为 null。

java 复制代码
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
	private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) {
		String name = info.name;
		if (info.name.isEmpty()) {
			name = parameter.getParameterName();
			if (name == null) {
				throw new IllegalArgumentException(
						"Name for argument of type [" + parameter.getNestedParameterType().getName() +
						"] not specified, and parameter name information not found in class file either.");
			}
		}
		String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue);
		return new NamedValueInfo(name, info.required, defaultValue);
	}
}

resolveEmbeddedValuesAndExpressions 方法用于解析参数中的占位符与 spring SpEL 表达式,其只有在 configurableBeanFactory 或 expressionContext 属性都不为空时才会进行解析,否则直接返回 value 参数值,其首先调用 configurableBeanFactory 对象工厂的 resolveEmbeddedValue 方法解析 value 中的 ${..} 占位符,随后调用 configurableBeanFactory 对象工厂中的 BeanExpressionResolver 表达式解析器的 evaluate 方法解析 #{expression} placeholdersResolved 变量中的 SpEL 表达式并返回解析结果。

java 复制代码
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
	@Nullable
	private Object resolveEmbeddedValuesAndExpressions(String value) {
		if (this.configurableBeanFactory == null || this.expressionContext == null) {
			return value;
		}
		String placeholdersResolved = this.configurableBeanFactory.resolveEmbeddedValue(value);
		BeanExpressionResolver exprResolver = this.configurableBeanFactory.getBeanExpressionResolver();
		if (exprResolver == null) {
			return value;
		}
		return exprResolver.evaluate(placeholdersResolved, this.expressionContext);
	}
}

3.3 内部类

3.3.1 NamedValueInfo 类

NamedValueInfo 方法用于标识参数的相关元数据,其中 name 为参数名称,required 属性标识是否必须,defaultValue 则是参数默认值。

java 复制代码
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
	protected static class NamedValueInfo {

		private final String name;

		private final boolean required;

		@Nullable
		private final String defaultValue;

		public NamedValueInfo(String name, boolean required, @Nullable String defaultValue) {
			this.name = name;
			this.required = required;
			this.defaultValue = defaultValue;
		}
	}
}

4 RequestParamMethodArgumentResolver 类

RequestParamMethodArgumentResolver 类用于 RequestParam 注解修饰的方法参数的解析。

4.1 属性

4.1.1 常量

RequestParamMethodArgumentResolver 类只有个保存字符串类型描述符的 STRING_TYPE_DESCRIPTOR 常量。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {

	private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
}

4.1.2 类变量

RequestParamMethodArgumentResolver 类也只有一个开关,用于标识当前解析器是否为默认解析器,主要标识是否可用于未获取到对应解析器的参数的解析。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	private final boolean useDefaultResolution;
}

4.2 方法

4.2.1 构造方法

RequestParamMethodArgumentResolver 类拥有两个构造方法,其提供了使用 ConfigurableBeanFactory 与 useDefaultResolution 标识创建对象;

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	public RequestParamMethodArgumentResolver(boolean useDefaultResolution) {
		this.useDefaultResolution = useDefaultResolution;
	}

	public RequestParamMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory,
			boolean useDefaultResolution) {

		super(beanFactory);
		this.useDefaultResolution = useDefaultResolution;
	}
}

4.2.2 supportsParameter 方法

supportsParameter 方法在参数拥有 RequestParam 注解时,参数类型不是 Map 直接返回,否则将会判断 RequestParam 对象是否拥有 name 值,只有拥有 name 属性值才会返回 true;而在没有 RequestParam 注解时,则首先会判断是否拥有 RequestPart 注解,拥有时直接返回 false,在参数为 Multipart 类型或其数组时也直接返回 true,否则只有在 useDefaultResolution 属性为 true 且参数为简单类型(基本数据类型 及其包装类、常见标准类型如 StringNumberDateURIURLLocaleClass 等或枚举类型)或其数组时才会返回 true,否则返回 false。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		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 {
			if (parameter.hasParameterAnnotation(RequestPart.class)) {
				return false;
			}
			parameter = parameter.nestedIfOptional();
			if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
				return true;
			}
			else if (this.useDefaultResolution) {
				return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
			}
			else {
				return false;
			}
		}
	}
}

4.2.3 createNamedValueInfo 方法

createNamedValueInfo 方法在参数的 RequestParam 注解不为空时,使用注解对象创建 RequestParamNamedValueInfo 对象,为空时创建空 RequestParamNamedValueInfo 对象并返回。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		RequestParam ann = parameter.getParameterAnnotation(RequestParam.class);
		return (ann != null ? new RequestParamNamedValueInfo(ann) : new RequestParamNamedValueInfo());
	}
}

4.2.4 resolveName 方法

resolveName 方法首先尝试将 request 请求转换为 HttpServletRequest 对象,在其不为空时,判断是否请求参数是否为 Mutipart 类型,若是则直接返回解析的 Mutipart 类型解析结果;之后尝试将 request 转换为 MultipartRequest 请求对象,转换成功后从其中获取 name 对应的文件列表并将对应文件对象保存到 arg 变量之中;若未获取到则会从 request 获取 name 对应 param 请求参数在其不为空时更新 arg 变量值,最后返回 arg 变量值。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	@Nullable
	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) {
			String[] paramValues = request.getParameterValues(name);
			if (paramValues != null) {
				arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
			}
		}
		return arg;
	}
}

4.2.5 handleMissingValue 方法

handleMissingValue 方法根据 request 参数的类型抛出不同的异常。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	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());
		}
	}
}

5 PathVariableMethodArgumentResolver 类

PathVariableMethodArgumentResolver 类用于路径参数的解析,由于其不存在拥有 ConfigurableBeanFactory 类型参数的构造方法,因此其参数名称及值不支持使用 ${...} 及 #{expression} 修饰来运行时解析。

5.1 常量

与 RequestParamMethodArgumentResolver 一样,PathVariableMethodArgumentResolver 类也有一个用于标识字符串类型描述符的 STRING_TYPE_DESCRIPTOR;

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {

	private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
}

5.2 方法

5.2.1 supportsParameter 方法

supportsParameter 方法在参数没有使用 PathVariable 注解修饰时直接返回 false,在参数类型为 Map 时则会返回 PathVariable 注解对象是否有 value 参数值,参数为其他类型则直接返回 true。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		if (!parameter.hasParameterAnnotation(PathVariable.class)) {
			return false;
		}
		if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
			PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
			return (pathVariable != null && StringUtils.hasText(pathVariable.value()));
		}
		return true;
	}
}

5.2.2 createNamedValueInfo 方法

createNamedValueInfo 方法直接使用 PathVariable 注解对象创建 PathVariableNamedValueInfo 对象并返回。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
		Assert.state(ann != null, "No PathVariable annotation");
		return new PathVariableNamedValueInfo(ann);
	}
}

5.2.3 resolveName 方法

resolveName 方法从 request 所绑定的 HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE 属性中获取 name 对应值并返回。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	@SuppressWarnings("unchecked")
	@Nullable
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
		Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(
				HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
		return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);
	}
}

5.2.4 handleMissingValue 方法

handleMissingValue 方法直接抛出 MissingPathVariableException 异常。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
		throw new MissingPathVariableException(name, parameter);
	}
}

5.2.5 handleResolvedValue 方法

handleResolvedValue 方法将当前解析参数以 name 与 value 映射的方式保存到 request 请求的 PATH_VARIABLES 属性之中以供之后使用。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	@Override
	@SuppressWarnings("unchecked")
	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);
		}
		pathVars.put(name, arg);
	}
}

5.3 PathVariableNamedValueInfo 内部类

PathVariableNamedValueInfo 内部类继承了 NamedValueInfo 方法扩展了使用 PathVariable 注解对象进行对象创建。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	private static class PathVariableNamedValueInfo extends NamedValueInfo {
		public PathVariableNamedValueInfo(PathVariable annotation) {
			super(annotation.name(), annotation.required(), ValueConstants.DEFAULT_NONE);
		}
	}
}

6 RequestHeaderMethodArgumentResolver 类

RequestHeaderMethodArgumentResolver 类用于 RequestHeader 修饰的请求头参数的解析;

6.1 方法

6.1.1 构造方法

RequestHeaderMethodArgumentResolver 类实现了带 ConfigurableBeanFactory 类型参数的构造方法。

java 复制代码
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	public RequestHeaderMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
		super(beanFactory);
	}
}

6.1.2 supportsParameter 方法

supportsParameter 方法直接返回当前属性是否不为 Map 对象且使用 RequestHeader 注解进行修饰;

java 复制代码
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return (parameter.hasParameterAnnotation(RequestHeader.class) &&
				!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()));
	}
}

6.1.3 createNamedValueInfo 方法

createNamedValueInfo 方法直接使用修饰参数的 RequestHeader 注解对象创建 RequestHeaderNamedValueInfo 对象并返回;

java 复制代码
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		RequestHeader ann = parameter.getParameterAnnotation(RequestHeader.class);
		Assert.state(ann != null, "No RequestHeader annotation");
		return new RequestHeaderNamedValueInfo(ann);
	}
}

6.1.4 resolveName 方法

resolveName 方法直接获取 request 对象对应请求值并返回;

java 复制代码
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	@Nullable
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
		String[] headerValues = request.getHeaderValues(name);
		if (headerValues != null) {
			return (headerValues.length == 1 ? headerValues[0] : headerValues);
		}
		else {
			return null;
		}
	}
}

6.1.5 handleMissingValue 方法

handleMissingValue 方法直接抛出 MissingRequestHeaderException 异常;

java 复制代码
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
		throw new MissingRequestHeaderException(name, parameter);
	}
}

6.2 RequestHeaderNamedValueInfo 内部类

RequestHeaderNamedValueInfo 内部类继承了 NamedValueInfo 方法扩展了使用 RequestHeader 注解对象进行对象创建。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
    public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
		private RequestHeaderNamedValueInfo(RequestHeader annotation) {
			super(annotation.name(), annotation.required(), annotation.defaultValue());
		}
	}
}

7 MatrixVariableMethodArgumentResolver 类

MatrixVariableMethodArgumentResolver 类为 MatrixVariable 修饰的矩阵参数的的解析,由于其不存在拥有 ConfigurableBeanFactory 类型参数的构造方法,因此其参数名称及值也不支持使用 ${...} 及 #{expression} 修饰来运行时解析。

7.1 方法

7.1.1 构造方法

MatrixVariableMethodArgumentResolver 类只有一个无参构造方法,未设置 ConfigurableBeanFactory 对象工厂对象。

java 复制代码
public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	public MatrixVariableMethodArgumentResolver() {
		super(null);
	}
}

7.1.2 supportsParameter 方法

supportsParameter 方法在参数为使用 MatrixVariable 参数修饰时直接返回 false,在参数为 Map 对象时,则会返回 MatrixVariable 对象的 value 是否有值,否则直接返回 true。

java 复制代码
public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		if (!parameter.hasParameterAnnotation(MatrixVariable.class)) {
			return false;
		}
		if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
			MatrixVariable matrixVariable = parameter.getParameterAnnotation(MatrixVariable.class);
			return (matrixVariable != null && StringUtils.hasText(matrixVariable.name()));
		}
		return true;
	}
}

7.1.3 createNamedValueInfo 方法

createNamedValueInfo 方法使用修饰参数的 MatrixVariable 对象创建 MatrixVariableNamedValueInfo 对象并返回。

java 复制代码
public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		MatrixVariable ann = parameter.getParameterAnnotation(MatrixVariable.class);
		Assert.state(ann != null, "No MatrixVariable annotation");
		return new MatrixVariableNamedValueInfo(ann);
	}
}

7.1.4 resolveName 方法

resolveName 方法首先获取在 RequestMappingInfoHandlerMapping 对象的单 mapping 参数 handleMatch 方法扩展中绑定到 request 请求对象上的 HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE 属性映射值,在其为空时直接返回 null;随后在注解的 pathVar 不为 ValueConstants.DEFAULT_NONE 时,从绑定的映射值中获取对应值 Map 并将 name 对应值保存到 paramValues 变量之中,否则遍历所有映射值,将其中的 name 对应值保存至 paramValues 变量之中,注意该情况下,不同映射值不允许拥有多个 name 对应值,存在则会抛出 ServletRequestBindingException 异常;最后在 paramValues 为空时直接返回 null,在其只有一个元素则会返回第一个元素,否则返回 paramValues。

java 复制代码
public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	@SuppressWarnings("unchecked")
	@Nullable
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
		Map<String, MultiValueMap<String, String>> pathParameters = (Map<String, MultiValueMap<String, String>>)
				request.getAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
		if (CollectionUtils.isEmpty(pathParameters)) {
			return null;
		}

		MatrixVariable ann = parameter.getParameterAnnotation(MatrixVariable.class);
		Assert.state(ann != null, "No MatrixVariable annotation");
		String pathVar = ann.pathVar();
		List<String> paramValues = null;

		if (!pathVar.equals(ValueConstants.DEFAULT_NONE)) {
			if (pathParameters.containsKey(pathVar)) {
				paramValues = pathParameters.get(pathVar).get(name);
			}
		}
		else {
			boolean found = false;
			paramValues = new ArrayList<>();
			for (MultiValueMap<String, String> params : pathParameters.values()) {
				if (params.containsKey(name)) {
					if (found) {
						String paramType = parameter.getNestedParameterType().getName();
						throw new ServletRequestBindingException(
								"Found more than one match for URI path parameter '" + name +
								"' for parameter type [" + paramType + "]. Use 'pathVar' attribute to disambiguate.");
					}
					paramValues.addAll(params.get(name));
					found = true;
				}
			}
		}

		if (CollectionUtils.isEmpty(paramValues)) {
			return null;
		}
		else if (paramValues.size() == 1) {
			return paramValues.get(0);
		}
		else {
			return paramValues;
		}
	}
}

7.1.5 handleMissingValue 方法

handleMissingValue 方法直接抛出 MissingMatrixVariableException 异常。

java 复制代码
public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
		throw new MissingMatrixVariableException(name, parameter);
	}
}

7.2 MatrixVariableNamedValueInfo 内部类

MatrixVariableNamedValueInfo 内部类继承了 NamedValueInfo 方法扩展了使用 MatrixVariable 注解对象进行对象创建。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
    public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
		private RequestHeaderNamedValueInfo(RequestHeader annotation) {
			super(annotation.name(), annotation.required(), annotation.defaultValue());
		}
	}
}

8 RequestAttributeMethodArgumentResolver 类

RequestAttributeMethodArgumentResolver 类为 RequestAttribute 修饰的请求属性解析;

8.1 方法

8.1.1 supportsParameter 方法

supportsParameter 方法直接返回参数是否使用 RequestAttribute 注解修饰。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(RequestAttribute.class);
	}
}
8.1.2 createNamedValueInfo 方法

createNamedValueInfo 方法使用 RequestAttribute 对象的 name、required 及 alueConstants.DEFAULT_NONE 值创建 NamedValueInfo 对象并返回。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		RequestAttribute ann = parameter.getParameterAnnotation(RequestAttribute.class);
		Assert.state(ann != null, "No RequestAttribute annotation");
		return new NamedValueInfo(ann.name(), ann.required(), ValueConstants.DEFAULT_NONE);
	}
}
8.1.3 resolveName 方法

resolveName 方法直接获取 request 中 name 对应属性值并返回。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	@Nullable
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request){
		return request.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
	}
}
8.1.4 handleMissingValue 方法

handleMissingValue 方法虽然同样也是抛出 ServletRequestBindingException 异常,但做出了对应适配。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
		throw new ServletRequestBindingException("Missing request attribute '" + name +
				"' of type " +  parameter.getNestedParameterType().getSimpleName());
	}
}

9 SessionAttributeMethodArgumentResolver 类

SessionAttributeMethodArgumentResolver 类为 SessionAttribute 修饰的请求属性解析;其实现基本与 RequestAttributeMethodArgumentResolver 一致,唯一的差别来自获取属性的作用域,RequestAttributeMethodArgumentResolver 类获取的是单次请求绑定的属性,而 SessionAttributeMethodArgumentResolver 则可获取整个会话中的对应属性。

java 复制代码
public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(SessionAttribute.class);
	}

	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		SessionAttribute ann = parameter.getParameterAnnotation(SessionAttribute.class);
		Assert.state(ann != null, "No SessionAttribute annotation");
		return new NamedValueInfo(ann.name(), ann.required(), ValueConstants.DEFAULT_NONE);
	}

	@Override
	@Nullable
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) {
		return request.getAttribute(name, RequestAttributes.SCOPE_SESSION);
	}

	@Override
	protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
		throw new ServletRequestBindingException("Missing session attribute '" + name +
				"' of type " + parameter.getNestedParameterType().getSimpleName());
	}

}

10 ExpressionValueMethodArgumentResolver 类

ExpressionValueMethodArgumentResolver 类实现的 Value 注解修饰的参数的解析,其值与单次请求无关,只与 Value 注解设置的 value 方法值有关。

10.1 方法

10.1.1 构造方法

ExpressionValueMethodArgumentResolver 的构造方法也是直接向父类提供 ConfigurableBeanFactory 对象工厂来进行对象创建。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	public ExpressionValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
		super(beanFactory);
	}
}

10.1.2 supportsParameter 方法

supportsParameter 方法直接返回 parameter 参数是否使用 Value 注解进行了修饰。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(Value.class);
	}
}

10.1.3 createNamedValueInfo 方法

createNamedValueInfo 方法直接使用 Value 对象创建 ExpressionValueNamedValueInfo 对象并返回。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		Value ann = parameter.getParameterAnnotation(Value.class);
		Assert.state(ann != null, "No Value annotation");
		return new ExpressionValueNamedValueInfo(ann);
	}
}

10.1.4 resolveName 方法

由于 Value 修饰的参数值与请求无关,直接使用 Value 注解中定义的 value 值进行解析,因此此处直接返回 null,表明使用 ExpressionValueNamedValueInfo 对象的默认值进行解析。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	@Nullable
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
		// No name to resolve
		return null;
	}
}

10.1.5 handleMissingValue 方法

handleMissingValue 方法直接抛出 UnsupportedOperationException 异常。

java 复制代码
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
		throw new UnsupportedOperationException("@Value is never required: " + parameter.getMethod());
	}
}

10.2 ExpressionValueNamedValueInfo 内部类

ExpressionValueNamedValueInfo 内部类继承了 NamedValueInfo 方法扩展了使用 Value 注解对象进行对象创建,其名称写死为 @Value,是否必填写死为 false,而默认值则使用 Value 对象的 value 方法配置值。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
    public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
		private RequestHeaderNamedValueInfo(RequestHeader annotation) {
			super(annotation.name(), annotation.required(), annotation.defaultValue());
		}
	}
}

11 ServletCookieValueMethodArgumentResolver 类

ServletCookieValueMethodArgumentResolver 类用于解析 CookieValue 注解修饰的参数。

11.1 AbstractCookieValueMethodArgumentResolver 抽象类

11.1.1 方法

构造方法

AbstractCookieValueMethodArgumentResolver 的构造方法也是直接向父类提供 ConfigurableBeanFactory 对象工厂来进行对象创建。

java 复制代码
public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	public AbstractCookieValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
		super(beanFactory);
	}
}
supportsParameter 方法

supportsParameter 方法 parameter 参数是否使用 CookieValue 注解进行修饰。

java 复制代码
public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(CookieValue.class);
	}
}
createNamedValueInfo 方法

createNamedValueInfo 方法直接使用 CookieValue 对象创建 CookieValueNamedValueInfo 对象并返回。

java 复制代码
public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		CookieValue annotation = parameter.getParameterAnnotation(CookieValue.class);
		Assert.state(annotation != null, "No CookieValue annotation");
		return new CookieValueNamedValueInfo(annotation);
	}
}
handleMissingValue 方法

handleMissingValue 方法直接抛出 MissingRequestCookieException 异常。

java 复制代码
public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		CookieValue annotation = parameter.getParameterAnnotation(CookieValue.class);
		Assert.state(annotation != null, "No CookieValue annotation");
		return new CookieValueNamedValueInfo(annotation);
	}
}
CookieValueNamedValueInfo 内部类

CookieValueNamedValueInfo 内部类继承了 NamedValueInfo 方法扩展了使用 CookieValue 注解对象进行对象创建。

java 复制代码
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
		implements UriComponentsContributor {
	private static final class CookieValueNamedValueInfo extends NamedValueInfo {

		private CookieValueNamedValueInfo(CookieValue annotation) {
			super(annotation.name(), annotation.required(), annotation.defaultValue());
		}
	}
}

11.2 属性

ServletCookieValueMethodArgumentResolver 类扩展了一个 urlPathHelper 路径解析辅助器属性。

java 复制代码
public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValueMethodArgumentResolver {

	private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance;

	public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
		this.urlPathHelper = urlPathHelper;
	}
}

11.3 方法

11.3.1 构造方法

ServletCookieValueMethodArgumentResolver 的构造方法也是直接向父类提供 ConfigurableBeanFactory 对象工厂来进行对象创建。

java 复制代码
public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValueMethodArgumentResolver {
	public ServletCookieValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
		super(beanFactory);
	}
}

11.3.2 resolveName 方法

resolveName 方法将 webRequest 参数转换为 HttpServletRequest 对象之后尝试从中获取 cookieName 对应 cookie 值,在参数类型就是 Cookie 时直接返回该 Cookie 对象,否则再起不为空时利用 urlPathHelper 将 cookie 解码然后返回,否则返回 null。

java 复制代码
public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValueMethodArgumentResolver {
	@Override
	@Nullable
	protected Object resolveName(String cookieName, MethodParameter parameter,
			NativeWebRequest webRequest) throws Exception {

		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
		Assert.state(servletRequest != null, "No HttpServletRequest");

		Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName);
		if (Cookie.class.isAssignableFrom(parameter.getNestedParameterType())) {
			return cookieValue;
		}
		else if (cookieValue != null) {
			return this.urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue());
		}
		else {
			return null;
		}
	}
}
相关推荐
郝学胜-神的一滴3 小时前
使用Linux系统函数递归遍历指定目录
linux·运维·服务器·开发语言·c++·软件工程
guygg883 小时前
Java 无锁方式实现高性能线程
java·开发语言
ss2734 小时前
手写Spring第7弹:Spring IoC容器深度解析:XML配置的完整指南
java·前端·数据库
青衫码上行4 小时前
【从0开始学习Java | 第22篇】反射
java·开发语言·学习
superlls4 小时前
(Spring)Spring Boot 中 @Valid 与全局异常处理器的联系详解
java·spring boot·后端
hmbbcsm4 小时前
python学习之路(四)
学习
Greedy Alg4 小时前
Socket编程学习记录
网络·websocket·学习
一念&4 小时前
每日一个C语言知识:C 字符串
c语言·开发语言
知识分享小能手4 小时前
uni-app 入门学习教程,从入门到精通,uni-app 基础知识详解 (2)
前端·javascript·windows·学习·微信小程序·小程序·uni-app