消息转化器的拓展,以及@ReqeustBody,@ResponseBody的实现

今天在使用其他传输协议的时候,踩了点坑,记录一下。
主要是针对Protobuf的应用时,不想去写手动转换字节的方式,这种方法太low了。
另外问题也会比较多。
像网上一些针对protobuf对象的转化,都是读取字节然后重新去构造一个对象。
代码如下,这是从网上看到的例子。 每次都要去转化,有点麻烦。


@Controller
@RequestMapping("/pbtest")
public class TestController {
    @RequestMapping("upload")
    public void upload(HttpServletRequest request, HttpServletResponse response) throws IOException {
        InputStream inputStream = request.getInputStream();
        AddressBook addressBook = AddressBook.parseFrom(inputStream);
        inputStream.close();
        System.out.println(addressBook);
    }
}

如何解决这个转化的问题。其实Spring本身已经提供了解决方案。就是mvc的消息转化器支持拓展。

springmvc自动装配的入口

具体源码如下,首先还是回到springmvc自动装配的入口

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
。。。内容省略
}

从上面的源码来看,有一个注解@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),这个注解就是提供拓展的关键,如果容器里面没有这个类型的bean,就默认使用WebMvcConfigurationSupport.class。

提供拓展的类WebMvcConfigurationSupport

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    @Nullable
    private List<HttpMessageConverter<?>> messageConverters;
    /**
     * Override this method to add custom {@link HttpMessageConverter HttpMessageConverters}
     * to use with the {@link RequestMappingHandlerAdapter} and the
     * {@link ExceptionHandlerExceptionResolver}.
     * <p>Adding converters to the list turns off the default converters that would
     * otherwise be registered by default. Also see {@link #addDefaultHttpMessageConverters}
     * for adding default message converters.
     * @param converters a list to add message converters to (initially an empty list)
     */
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }
}

里面的这个方法,其实就是springmvc给我们提供用来拓展消息转化器的方法。

如何实现

@Configuration
public class CustomWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
    //添加protobuf转化器
    @Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new ProtobufHttpMessageConverter());
    }
}

另外controller中还是跟以前一样,切记@RequestBody与@ResponseBody都不能丢,否则入参不会被消息转化器处理。
@Controller
@RequestMapping("/demo")
public class DemoController {
    
    @Autowired
    private PersonApiService personApiService;
    
    @PostMapping("/addPerson")
    @ResponseBody
    public Response addPerson(@RequestBody AddPerson addPerson) throws IOException {
        return personApiService.addPerson(addPerson);
    }
    
    
}

ProtobufHttpMessageConverter如何处理对应的请求里的参数?

public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<Message> {
    @Override
    protected boolean supports(Class<?> clazz) {
        return Message.class.isAssignableFrom(clazz);
    }

    @Override
    public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
        return supports(clazz) && canRead(mediaType);
    }
    @Override
    public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
        return supports(clazz) && canWrite(mediaType);
    }
}

从上面方法来看,能不能读或者写,完全是看入参是不是Message类型。Message是protobuf对象的一个通用类型。

原理

需要用到的类

HttpMessageConverter

消息转化器,其实就是用于处理http请求中传输的内容,根据协议进行转化。
常见的有包括处理json,xml,以及其他各种协议的消息转化器

public interface HttpMessageConverter<T> {
    boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
    boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
    List<MediaType> getSupportedMediaTypes();
    T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException;
    void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException;

}

AbstractHttpMessageConverter

进行了部分实现

    @Override
    public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
        return supports(clazz) && canRead(mediaType);
    }

    protected boolean canRead(@Nullable MediaType mediaType) {
        if (mediaType == null) {
            return true;
        }
        通过请求头判断能不能读
        for (MediaType supportedMediaType : getSupportedMediaTypes()) {
            if (supportedMediaType.includes(mediaType)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
        return supports(clazz) && canWrite(mediaType);
    }

    protected boolean canWrite(@Nullable MediaType mediaType) {
        if (mediaType == null || MediaType.ALL.equalsTypeAndSubtype(mediaType)) {
            return true;
        }
        通过请求头判断能不能写
        for (MediaType supportedMediaType : getSupportedMediaTypes()) {
            if (supportedMediaType.isCompatibleWith(mediaType)) {
                return true;
            }
        }
        return false;
    }
        暴露给子类去实现的类型判断
    protected abstract boolean supports(Class<?> clazz);

HandlerMethodArgumentResolver

这个类是用于解析请求的入参,主要提供了2方法,一个是判断是否支持解析,其次就是如何解析。

public interface HandlerMethodArgumentResolver {

    /**
     * Whether the given {@linkplain MethodParameter method parameter} is
     * supported by this resolver.
     * @param parameter the method parameter to check
     * @return {@code true} if this resolver supports the supplied parameter;
     * {@code false} otherwise
     */
    boolean supportsParameter(MethodParameter parameter);

    /**
     * Resolves a method parameter into an argument value from a given request.
     * A {@link ModelAndViewContainer} provides access to the model for the
     * request. A {@link WebDataBinderFactory} provides a way to create
     * a {@link WebDataBinder} instance when needed for data binding and
     * type conversion purposes.
     * @param parameter the method parameter to resolve. This parameter must
     * have previously been passed to {@link #supportsParameter} which must
     * have returned {@code true}.
     * @param mavContainer the ModelAndViewContainer for the current request
     * @param webRequest the current request
     * @param binderFactory a factory for creating {@link WebDataBinder} instances
     * @return the resolved argument value, or {@code null} if not resolvable
     * @throws Exception in case of errors with the preparation of argument values
     */
    @Nullable
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}

看源码接口结构比较简单,可以看看其对应的一些实现类。
RequestResponseBodyMethodProcessor就是其对应的一个实现类。专门用于处理@RequestBody以及@ResponseBody。这个可以后面再说

AbstractMessageConverterMethodArgumentResolver

这个类的作用就是定义了如何利用消息转化器来解析参数

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
    protected final List<HttpMessageConverter<?>> messageConverters;
    protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
            Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
         内容暂时省略
         }
}

HandlerMethodArgumentResolverComposite

复合参数解析器,就是一个组合的参数解析器

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

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

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

HandlerMethodReturnValueHandler

这个类则是专门用于处理返回结果。RequestResponseBodyMethodProcessor的对于@ResponseBody处理的实现,也是基于此接口。

public interface HandlerMethodReturnValueHandler {
    boolean supportsReturnType(MethodParameter returnType);
    void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}

AbstractMessageConverterMethodProcessor

这个类则是一个抽象类,具备了参数解析的功能(通过继承AbstractMessageConverterMethodArgumentResolver),以及处理返回结果的功能,至于如何处理返回结果则是通过定义writeWithMessageConverters方法。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
        implements HandlerMethodReturnValueHandler {
    protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
        writeWithMessageConverters(value, returnType, inputMessage, outputMessage);
    }
    @SuppressWarnings({"rawtypes", "unchecked"})
    protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
            ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
             。。。代码暂时忽略,实现内容有点多。主要就是通过消息转化器来处理返回结果。
    }
}

RequestResponseBodyMethodProcessor

这个类则是专门用于处理@RequestBody以及@ResponseBody。从结构看一目了然。它继承的抽象类,本身定义好了对于入参的解析,以及响应返回值的处理。

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestBody.class);
    }

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                returnType.hasMethodAnnotation(ResponseBody.class));
    }
}

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
        implements HandlerMethodReturnValueHandler {
}

HandlerMethod

这个类看上去内容挺多的,但是其实是对于一个bean如何处理的封装。
bean以及对应的处理方法。

public class HandlerMethod {
    protected final Log logger = LogFactory.getLog(getClass());

    private final Object bean;

    @Nullable
    private final BeanFactory beanFactory;

    private final Class<?> beanType;

    private final Method method;

    private final Method bridgedMethod;

    private final MethodParameter[] parameters;

    @Nullable
    private HttpStatus responseStatus;

    @Nullable
    private String responseStatusReason;

    @Nullable
    private HandlerMethod resolvedFromHandlerMethod;

    @Nullable
    private volatile List<Annotation[][]> interfaceParameterAnnotations;

    private final String description;


    /**
     * Create an instance from a bean instance and a method.
     */
    public HandlerMethod(Object bean, Method method) {
        Assert.notNull(bean, "Bean is required");
        Assert.notNull(method, "Method is required");
        this.bean = bean;
        this.beanFactory = null;
        this.beanType = ClassUtils.getUserClass(bean);
        this.method = method;
        this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
        this.parameters = initMethodParameters();
        evaluateResponseStatus();
        this.description = initDescription(this.beanType, this.method);
    }

}

InvocableHandlerMethod

这个类是HandlerMethod的子类,主要是提供执行方法的功能。而其父类则是关注对象与方法的封装。

public class InvocableHandlerMethod extends HandlerMethod {
    复合的参数解析器
    private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();

    @Nullable
    public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        //解析参数
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            logger.trace("Arguments: " + Arrays.toString(args));
        }
        //对参数进行处理-最后返回结果
        return doInvoke(args);
    }

    解析请求中的参数
    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        MethodParameter[] parameters = getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        }

        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            。。。省略部分代码
            判断参数解析器中是否有可以解析该参数的
            if (!this.resolvers.supportsParameter(parameter)) {
                throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
            }
            try {
                对参数进行解析
                args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
            }
            catch (Exception ex) {
                // Leave stack trace for later, exception may actually be resolved and handled...
                if (logger.isDebugEnabled()) {
                    String exMsg = ex.getMessage();
                    if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                        logger.debug(formatArgumentError(parameter, exMsg));
                    }
                }
                throw ex;
            }
        }
        return args;
    }
}

ServletInvocableHandlerMethod

这个类其实挺复杂的,但是功能上主要是涵盖了解析请求入参,以及生成响应结果。

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod{
    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
         //父类中的实现,InvocableHandlerMethod中。
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                disableContentCachingIfNecessary(webRequest);
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(getResponseStatusReason())) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        Assert.state(this.returnValueHandlers != null, "No return value handlers");
        try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(formatErrorForReturnValue(returnValue), ex);
            }
            throw ex;
        }
    }}

源码的执行过程

首先一个请求被处理的入口还是在DispatcherServlet,代码如下

public class DispatcherServlet extends FrameworkServlet {
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
                找到请求匹配的处理器链(拦截器 过滤器 controller对应的执行方法)
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    没有找到对应的处理器直接返回
                    noHandlerFound(processedRequest, response);
                    return;
                }

                将Controller中的执行方法转化处理器适配器  
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                ...
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                通过适配器进行处理,返回视图,这里就包括了参数的解析,以及响应的生成,所以接下来看里面的实现即可
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                ....
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
                     ....
        }
        finally {
                      ...省略代码
        }
    }

}

那么HandlerAdapter如何去进行请求入参的解析,以及响应的生成?

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
        implements BeanFactoryAware, InitializingBean {
    @Nullable
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
                        ...省略
            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
                        ...省略若干代码
                        这里看到,其实是HandlerMethod的子类,ServletInvocableHandlerMethod 去执行的。
                        前面说到这个类,是用于解析请求入参,以及生成响应结果。那么接下来看看如何处理。
            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }

            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }

}

由于ServletInvocableHandlerMethod中解析参数以及生成响应结果的操作是在父类中去实现的。
所以接下来直接看父类InvocableHandlerMethod如何实现的。

public class InvocableHandlerMethod extends HandlerMethod {
    复合解析器
    private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        MethodParameter[] parameters = getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        }

        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            ...省略代码
            通过复合解析器判断是否有支持的参数解析器,若无则报错
            if (!this.resolvers.supportsParameter(parameter)) {
                throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
            }
            try {
                通过复合解析器去进行参数的解析
                args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
            }
            catch (Exception ex) {
                // Leave stack trace for later, exception may actually be resolved and handled...
                if (logger.isDebugEnabled()) {
                    String exMsg = ex.getMessage();
                    if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                        logger.debug(formatArgumentError(parameter, exMsg));
                    }
                }
                throw ex;
            }
        }
        return args;
    }
}

复合解析器如何去判断是否支持参数的解析
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return getArgumentResolver(parameter) != null;
    }

    @Nullable
    private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
        缓存不存在则进行遍历
        if (result == null) {
            for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
                参数解析器链中,那么@RqesutBody的参数以及@ResponseBody的响应如何判断是否支持?
                if (resolver.supportsParameter(parameter)) {
                    result = resolver;
                    this.argumentResolverCache.put(parameter, result);
                    break;
                }
            }
        }
        return result;
    }
}

那么@RqesutBody的参数以及@ResponseBody的响应如何判断是否支持?
其实就是判断是否有对应的注解修饰。
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestBody.class);
    }

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                returnType.hasMethodAnnotation(ResponseBody.class));
    }

}

从上面的代码看到被@RequestBody以及@ResponseBody注解修饰的参数,都会被RequestResponseBodyMethodProcessor 处理。

那么RequestResponseBodyMethodProcessor如何解析@RequsetBody修饰的参数?

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

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @SuppressWarnings("unchecked")
    @Nullable
    protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
            Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

        省略部分代码....
        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);
                判断消息转换器是否能读取。一个是通过参数的类型,另外一个通过请求头ContentType。
                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);
                        使用消息转化器的read方法,进行参数的读取
                        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);
        }
        ...省略代码
        return body;
    }
}

那么由于我测试使用的协议是protobuf,那么Protobuf的消息转化器如何起作用?

public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<Message> {
    从代码中看出,能不能读除了类型判断,还有contenttype的判断。
    需要类型为Message&mediaType为application/x-protobuf
    @Override
    public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
        return supports(clazz) && canRead(mediaType);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        为Message的子类
        return Message.class.isAssignableFrom(clazz);
    }

    @Override
    protected Message readInternal(Class<? extends Message> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {

        MediaType contentType = inputMessage.getHeaders().getContentType();
        if (contentType == null) {
            contentType = PROTOBUF;
        }
        Charset charset = contentType.getCharset();
        if (charset == null) {
            charset = DEFAULT_CHARSET;
        }

        Message.Builder builder = getMessageBuilder(clazz);
        if (PROTOBUF.isCompatibleWith(contentType)) {
            builder.mergeFrom(inputMessage.getBody(), this.extensionRegistry);
        }
        else if (TEXT_PLAIN.isCompatibleWith(contentType)) {
            InputStreamReader reader = new InputStreamReader(inputMessage.getBody(), charset);
            TextFormat.merge(reader, this.extensionRegistry, builder);
        }
        else if (this.protobufFormatSupport != null) {
            this.protobufFormatSupport.merge(
                    inputMessage.getBody(), charset, contentType, this.extensionRegistry, builder);
        }
        返回参数
        return builder.build();
    }
}
public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T> {
    protected boolean canRead(@Nullable MediaType mediaType) {
        if (mediaType == null) {
            return true;
        }
        for (MediaType supportedMediaType : getSupportedMediaTypes()) {
            if (supportedMediaType.includes(mediaType)) {
                return true;
            }
        }
        return false;
    }
}

前面的内容基本就大概知道@ReqeustBody是如何起作用的了。那么对于@ResponseBody的处理是如何的?

@ResponseBody的处理

先回到InvocableHandlerMethod,源码如下

public class InvocableHandlerMethod extends HandlerMethod {
    private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();

    @Nullable
    public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        解析完参数后
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            logger.trace("Arguments: " + Arrays.toString(args));
        }
        让controller的方法invoke执行,最后返回结果
        return doInvoke(args);
    }
}

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
    复合处理器
    @Nullable
    private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        解析入参,并且Invoke controller的处理方法,获得返回值
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        省略代码。。。
        try {
            最后对结果进行处理。
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(formatErrorForReturnValue(returnValue), ex);
            }
            throw ex;
        }
    }
}

从上面的代码可以看到,其实是通过returnValueHandlers,这个复合处理器来处理返回结果的。
那么这个复合处理器自然包括我们前面提到的RequestResponseBodyMethodProcessor。
那么这个复合处理器如何工作的?

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
    维护了一个处理器链,处理器链包含RequestResponseBodyMethodProcessor
    private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        选择合适的处理器
        HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
        if (handler == null) {
            throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
        }
         处理器对返回值进行处理
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }
    @Nullable
    private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
        boolean isAsyncValue = isAsyncReturnValue(value, returnType);
        for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
            if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
                continue;
            }
            if (handler.supportsReturnType(returnType)) {
                return handler;
            }
        }
        return null;
    }
}

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                returnType.hasMethodAnnotation(ResponseBody.class));
    }
}

RequestResponseBodyMethodProcessor如何处理返回值

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
        mavContainer.setRequestHandled(true);
        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
        通过消息转化器来转化响应结果
        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
    }
}

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
        implements HandlerMethodReturnValueHandler {

    @SuppressWarnings({"rawtypes", "unchecked"})
    protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
            ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

        Object body;
        Class<?> valueType;
        Type targetType;

        if (value instanceof CharSequence) {
            body = value.toString();
            valueType = String.class;
            targetType = String.class;
        }
        else {
            body = value;
            返回值的类型
            valueType = getReturnValueType(body, returnType);
            targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
        }

        if (selectedMediaType != null) {
            selectedMediaType = selectedMediaType.removeQualityValue();
            for (HttpMessageConverter<?> converter : this.messageConverters) {
                通过消息转化器对返回值进行处理
                GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
                        (GenericHttpMessageConverter<?>) converter : null);
                先判断是否消息转化器是否匹配,由于我在debug的时候,返回的是Message类型,即Protobuf指定的类型。所以序列化当然也是以Protobuf的消息转化器去做。
                if (genericConverter != null ?
                        ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
                        converter.canWrite(valueType, selectedMediaType)) {
                    body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
                            (Class<? extends HttpMessageConverter<?>>) converter.getClass(),
                            inputMessage, outputMessage);
                    if (body != null) {
                        Object theBody = body;
                        addContentDispositionHeader(inputMessage, outputMessage);
                        if (genericConverter != null) {
                            genericConverter.write(body, targetType, selectedMediaType, outputMessage);
                        }
                        else {
                            protobuf消息转换器的写方法,进行序列化
                            ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
                        }
                    }
                    else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Nothing to write: null body");
                        }
                    }
                    return;
                }
            }
        }
    }
}

最后Protobuf消息处理器写入数据

public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<Message> {
    @SuppressWarnings("deprecation")
    @Override
    protected void writeInternal(Message message, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {

        MediaType contentType = outputMessage.getHeaders().getContentType();
        if (contentType == null) {
            contentType = getDefaultContentType(message);
            Assert.state(contentType != null, "No content type");
        }
        Charset charset = contentType.getCharset();
        if (charset == null) {
            charset = DEFAULT_CHARSET;
        }

        if (PROTOBUF.isCompatibleWith(contentType)) {
            setProtoHeader(outputMessage, message);
            CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputMessage.getBody());
            序列化的同时,写入到对应的流中
            message.writeTo(codedOutputStream);
            codedOutputStream.flush();
        }
        else if (TEXT_PLAIN.isCompatibleWith(contentType)) {
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputMessage.getBody(), charset);
            TextFormat.print(message, outputStreamWriter);  // deprecated on Protobuf 3.9
            outputStreamWriter.flush();
            outputMessage.getBody().flush();
        }
        else if (this.protobufFormatSupport != null) {
            this.protobufFormatSupport.print(message, outputMessage.getBody(), contentType, charset);
            outputMessage.getBody().flush();
        }
    }

}

总结:
请求的处理大致可以分为3步。
1.对于请求入参的解析。无非是通过复合参数解析器中的参数解析器链表,根据入参的类型来判断。比如RequestResponseBodyMethodProcessor的实现,针对@RequestBody的处理,便是通过入参是否被@ReqeustBody修饰,判断能否被处理。其次便是参数解析器中的消息转化器来根据入参的类型以及请求头Contenttype决定是否能被对应的消息转化器处理。如利用Protobuf转化协议,那么入参类型必为Message的子类且contentType=x-protobuf。最后被protobuf的消息转化器进行反序列化。
2.controller中的方法进行invoke生成返回值
3.将controller方法中返回的结果进行序列化。那么这里也是通过复合返回值处理器进行处理。比如RequestResponseBodyMethodProcessor针对@ResponseBody的处理。首先是判断返回类型是否被@ResponseBody注解修饰,其次再通过其内部的消息转化器进行处理。那么消息转化器的处理,也是判断返回类型,比如ProtobufHttpMessageConverter也是判断返回的对象类型是否为Message的子类且contentType=x-protobuf,最后才会进行反序列化,写入响应对应的输出流中。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容