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 且参数为简单类型(基本数据类型 及其包装类、常见标准类型如 String
、Number
、Date
、URI
、URL
、Locale
、Class 等
或枚举类型)或其数组时才会返回 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;
}
}
}