SpringFramework之RequestBodyAdvice

编程

    Spring版本5.1.4.release.

    本来RequestBodyAdvice和ResponseBodyAdvice是成对一起的,这里先分析RequestBodyAdvice.

    List-1

public interface RequestBodyAdvice {

boolean supports(MethodParameter methodParameter, Type targetType,

Class<? extends HttpMessageConverter<?>> converterType);

HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,

Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException;

Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,

Type targetType, Class<? extends HttpMessageConverter<?>> converterType);

@Nullable

Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,

Type targetType, Class<? extends HttpMessageConverter<?>> converterType);

}

    如List-1所示, 看到supports方法就应该想到使用到了模板设计模式, 那么在哪使用到的呢?

    RequestBodyAdvice,只有在@RequestBody注解的方法时才有效,为什么呢? 

    一切的一切要从RequestResponseBodyMethodProcessor类上说起,如下图1,实现了HandlerMethodArgumentResolver

                                                                           图1

    RequestResponseBodyMethodProcessor类实现了HandlerMethodArgumentResolver接口, 使用到@RequestBody注解才会让RequestBodyAdvice生效就是这里导致的,如下List-2,只有supportsParameter返回true,调用调用resolveArgument方法.

    List-2

public interface HandlerMethodArgumentResolver {

boolean supportsParameter(MethodParameter var1);

@Nullable

Object resolveArgument(MethodParameter var1, @Nullable ModelAndViewContainer var2, NativeWebRequest var3, @Nullable WebDataBinderFactory var4) throws Exception;

}

    List-3

RequestResponseBodyMethodProcessor{

...

@Override

public boolean supportsParameter(MethodParameter parameter) {

return parameter.hasParameterAnnotation(RequestBody.class);

}

@Override

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,

NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

...

Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());

...

return adaptArgumentIfNecessary(arg, parameter);

}

...

}

    如上List-3,RequestResponseBodyMethodProcessor的supportsParameter方法中判断方法上是否有RequestBody注解,所以如果方法上没有此注解,那么RequestResponseBodyMethodProcessor的resolveArgument方法就不会被调用,而调用RequestBodyAdice的代码就在resolveArgument方法的readWithMessageConverters中。

    RequestResponseBodyMethodProcessor.readWithMessageConverters()会间接调用父类AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters方法,如下List-4

    List-4

AbstractMessageConverterMethodArgumentResolver{

...

protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,

Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

  ...

EmptyBodyCheckingHttpInputMessage message;

try {

message = new EmptyBodyCheckingHttpInputMessage(inputMessage);

    //1

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()) {

       //2

HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType);

body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :

((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));

//3

       body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);

}

else {

       //4

body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);

}

break;

}

}

}

...

return body;

}

...

}

  1. 遍历HttpMessageConverter,找到能处理解析请求参数的Converter
  2. 在读取body前,调用RequestBodyAdvice的beforeBodyRead
  3. 在读取body后,调用RequestBodyAdvice的afterBodyRead
  4. 如果请求的消息体为空,则调用RequestBodyAdvice的handleEmptyBody

    AbstractMessageConverterMethodArgumentResolver中getAdvice方法返回的是RequestResponseBodyAdviceChain,看类名就知道使用到了链式设计模式。如下List-5,方法before/afterBodyRead中遍历requstBodyAdvice,逐个调用RequestBodyAdvice的supports方法,如果返回true则再调用before/afterBodyAdvice.

    List-5

class RequestResponseBodyAdviceChain implements RequestBodyAdvice, ResponseBodyAdvice<Object> {

private final List<Object> requestBodyAdvice = new ArrayList<>(4);

private final List<Object> responseBodyAdvice = new ArrayList<>(4);

...

@Override

public HttpInputMessage beforeBodyRead(HttpInputMessage request, MethodParameter parameter,

Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {

for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {

if (advice.supports(parameter, targetType, converterType)) {

request = advice.beforeBodyRead(request, parameter, targetType, converterType);

}

}

return request;

}

@Override

public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,

Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {

for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {

if (advice.supports(parameter, targetType, converterType)) {

body = advice.afterBodyRead(body, inputMessage, parameter, targetType, converterType);

}

}

return body;

}

@Override

@Nullable

public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,

Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {

for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {

if (advice.supports(parameter, targetType, converterType)) {

body = advice.handleEmptyBody(body, inputMessage, parameter, targetType, converterType);

}

}

return body;

}

...

}

    到此,我们知道了RequestBodyAdvice可以修改spring解析出的参数,而后再传入到controller类的方法上,后续我会讲解如何使用RequestBodyAdvice特性来处理业务问题.

以上是 SpringFramework之RequestBodyAdvice 的全部内容, 来源链接: utcz.com/z/517930.html

回到顶部