当前位置: 首页 > news >正文

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

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

public interface HandlerMethodArgumentResolver {boolean supportsParameter(MethodParameter parameter);@NullableObject resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;}

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

1. HandlerMethodArgumentResolverComposite 

1.1 属性

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

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 方法获取对应解析器,然后在执行对应动作;

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {return getArgumentResolver(parameter) != null;}@Override@Nullablepublic 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 缓存并返回。

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {@Nullableprivate 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。

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。

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 属性之中。 

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 媒体类型,在去重、排序后返回。

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 方法继续读取并返回;

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {@Nullableprotected <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,不满足上述所有条件则会直接抛出异常。

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {@Nullableprotected <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 对其进行封装并返回,否则抛出异常。

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 方法来进行验证。

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 的子类进行判断的。

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 类型参数。

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {@Nullableprotected 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,扩展了空请求体检验功能。

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {private static class EmptyBodyCheckingHttpInputMessage implements HttpInputMessage {private final HttpHeaders headers;@Nullableprivate 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);}}}@Overridepublic HttpHeaders getHeaders() {return this.headers;}@Overridepublic 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 参数。

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {@Overridepublic 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 对象。

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {@Overrideprotected <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 属性

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {@Nullableprivate final ConfigurableBeanFactory configurableBeanFactory;@Nullableprivate final BeanExpressionContext expressionContext;private final Map<MethodParameter, NamedValueInfo> namedValueInfoCache = new ConcurrentHashMap<>(256);
}

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

3.2 方法

3.2.1 构造方法

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 方法进一步处理完成解析的参数并返回。

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {@Override@Nullablepublic 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;}@Nullableprotected abstract Object resolveName(String name, MethodParameter parameter, NativeWebRequest request)throws Exception;@Nullableprivate 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 缓存后返回。

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。

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 表达式并返回解析结果。

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {@Nullableprivate 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 则是参数默认值。

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {protected static class NamedValueInfo {private final String name;private final boolean required;@Nullableprivate 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 常量。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
}

4.1.2 类变量

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

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {private final boolean useDefaultResolution;
}

4.2 方法

4.2.1 构造方法

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

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements 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。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {@Overridepublic 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 对象并返回。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {@Overrideprotected 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 变量值。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {@Override@Nullableprotected 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 参数的类型抛出不同的异常。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {@Overrideprotected 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;

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements 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。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {@Overridepublic 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 对象并返回。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {@Overrideprotected 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 对应值并返回。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {@Override@SuppressWarnings("unchecked")@Nullableprotected 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 异常。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {@Overrideprotected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {throw new MissingPathVariableException(name, parameter);}
}

5.2.5 handleResolvedValue 方法

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

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements 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 注解对象进行对象创建。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements 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 类型参数的构造方法。

public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {public RequestHeaderMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {super(beanFactory);}
}

6.1.2 supportsParameter 方法

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

public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {return (parameter.hasParameterAnnotation(RequestHeader.class) &&!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()));}
}

6.1.3 createNamedValueInfo 方法

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

public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected 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 对象对应请求值并返回;

public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Override@Nullableprotected 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 异常;

public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {throw new MissingRequestHeaderException(name, parameter);}
}

6.2 RequestHeaderNamedValueInfo 内部类

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

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements 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 对象工厂对象。

public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {public MatrixVariableMethodArgumentResolver() {super(null);}
}

7.1.2 supportsParameter 方法

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

public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overridepublic 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 对象并返回。

public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected 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。

public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Override@SuppressWarnings("unchecked")@Nullableprotected 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 异常。

public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {throw new MissingMatrixVariableException(name, parameter);}
}

7.2 MatrixVariableNamedValueInfo 内部类

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

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements 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 注解修饰。

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(RequestAttribute.class);}
}
8.1.2 createNamedValueInfo 方法

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

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected 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 对应属性值并返回。

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Override@Nullableprotected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request){return request.getAttribute(name, RequestAttributes.SCOPE_REQUEST);}
}
8.1.4 handleMissingValue 方法

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

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected 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 则可获取整个会话中的对应属性。

public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(SessionAttribute.class);}@Overrideprotected 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@Nullableprotected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) {return request.getAttribute(name, RequestAttributes.SCOPE_SESSION);}@Overrideprotected 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 对象工厂来进行对象创建。

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {public ExpressionValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {super(beanFactory);}
}

10.1.2 supportsParameter 方法

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

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(Value.class);}
}

10.1.3 createNamedValueInfo 方法

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

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected 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 对象的默认值进行解析。

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Override@Nullableprotected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {// No name to resolvereturn null;}
}

10.1.5 handleMissingValue 方法

        handleMissingValue 方法直接抛出 UnsupportedOperationException 异常。

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected 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 方法配置值。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements 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 对象工厂来进行对象创建。

public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {public AbstractCookieValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {super(beanFactory);}
}
  •  supportsParameter 方法

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

public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(CookieValue.class);}
}
  •  createNamedValueInfo 方法

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

public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {CookieValue annotation = parameter.getParameterAnnotation(CookieValue.class);Assert.state(annotation != null, "No CookieValue annotation");return new CookieValueNamedValueInfo(annotation);}
}
  •   handleMissingValue 方法

        handleMissingValue 方法直接抛出 MissingRequestCookieException 异常。

public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {@Overrideprotected 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 注解对象进行对象创建。

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolverimplements UriComponentsContributor {private static final class CookieValueNamedValueInfo extends NamedValueInfo {private CookieValueNamedValueInfo(CookieValue annotation) {super(annotation.name(), annotation.required(), annotation.defaultValue());}}
}

11.2 属性

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

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 对象工厂来进行对象创建。

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。

public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValueMethodArgumentResolver {@Override@Nullableprotected 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;}}
}

    http://www.dtcms.com/a/503353.html

    相关文章:

  • Git拉取代码报无权限的错误处理方案
  • 棋牌网站管理后台嗅探查找方法(2025最新)
  • 沈阳微信网站建设大连网站建设开发
  • 中英文企业网站模板wordpress插件 标签
  • 生成式引擎优化(GEO):五大 AI 引擎赋能多场景的技术与实践指南
  • 从邮票到Labubu:四十年中国收藏与潮流风潮的演变逻辑
  • 天猫网站左侧导航是怎么做的青岛建站推广
  • Linux中I2C常见问题三
  • C++初阶(14)list
  • python进阶刷题8
  • 完成职教集团网站建设唐山市做网站
  • 19.7 ChatPPT v2.0语音识别实战:3秒极速响应+88.7%准确率的Whisper模型黑科技
  • Cortex-M3 内核 MCU-STM32F1 开发之路:(二)寄存器地址的计算
  • 完整开发网站需要什么访问域名
  • Photoshop - Photoshop 工具栏(14)抓手工具
  • MySQL 之索引为什么选择B+树
  • seo网站页面f布局如何做企业文化培训
  • C语言-数组
  • 01-(JavaWeb)前端部分(HTML+CSS)
  • Sendable装饰器的使用
  • 产品经理做网站东莞网站搭建
  • vue3中的watch使用
  • SQL Server安全配置全面检查与优化方案
  • 唐山市城乡建设局网站哪个网站做的系统好用吗
  • 包头市建设厅官方网站开网店详细步骤流程
  • 什么是前端、后端与全栈开发,Qt属于什么?
  • Solidity 合约超限问题及优化策略:以 FHEFactory 为例
  • 第一届贵州理工校赛--ez-uploadez-upload-plus
  • 聊聊 Unity(小白专享、C# 小程序 之 联机对战)
  • ava编辑一个小程序操作教程分享一下C++