深入分析Spring MVC中RequestBody与ResponseBody

  在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换。在Spring MVC内部是如何做到的呢?先记住下面这张图,然后对里面的每个对象进行分析:
  • HttpInputMessage
    HttpInputMessage是对一次Http请求报文的抽象。接口定义了getBody方法用于得到http请求的InputStream对象。具体的接口定义如下:
package org.springframework.http;

import java.io.IOException;
import java.io.InputStream;

public interface HttpInputMessage extends HttpMessage {

    /**
     * Return the body of the message as an input stream.
     * @return the input stream body
     * @throws IOException in case of I/O Errors
     */
    InputStream getBody() throws IOException;

}
  • HttpOutputMessage
    HttpOutputMessage是SpringMVC内部对一次Http响应报文的抽象,接口定义了getBody方法用于得到输出数据的OutputStream对象。源码如下:
package org.springframework.http;

import java.io.IOException;
import java.io.OutputStream;
public interface HttpOutputMessage extends HttpMessage {

    /**
     * Return the body of the message as an output stream.
     * @return the output stream body
     * @throws IOException in case of I/O Errors
     */
    OutputStream getBody() throws IOException;

}
  • HttpMessageConverter
    对消息转换器最高层次的接口抽象,描述了一个消息转换器的一般特征。源代码如下:
package org.springframework.http.converter;

import java.io.IOException;
import java.util.List;

import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;


public interface HttpMessageConverter<T> {

//根据clazz与mediaType判断当前Converter是否能进行读操作
    boolean canRead(Class<?> clazz, MediaType mediaType);
//根据clazz与mediaType判断当前Converter是否能进行写操作
    boolean canWrite(Class<?> clazz, MediaType mediaType);
//得到支持的MediaType
    List<MediaType> getSupportedMediaTypes();
//读方法 通过inputMessage能够得到http的输入流,然后转成业务对象T
    T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException;
//写方法,通过outputMessage能够得到http的输出流,然后将T对象写出
    void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException;

}

光有接口定义是不行的, 还得有具体的实现才能够实现请求报文与对象之间的转换,下面我们来看看我们熟悉的json对象是如何来进行转换的。我们实际的业务会用到阿里的fastjson,fastjson通过FastJsonHttpMessageConverter这个类来实现对json数据的转换,我们先来看看FastJsonHttpMessageConverter的父类AbstractHttpMessageConverter的逻辑,代码如下:

package org.springframework.http.converter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;

public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T> {

    protected final Log logger = LogFactory.getLog(getClass());
//这里维护了支持的MediaType类型,是个集合对象 
    private List<MediaType> supportedMediaTypes = Collections.emptyList();
//下面三个方法是构造方法,
    protected AbstractHttpMessageConverter() {
    }
//这里需要传入一个MediaType对象
    protected AbstractHttpMessageConverter(MediaType supportedMediaType) {
        setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
    }
//这里需要传入一组MediaType对象
    protected AbstractHttpMessageConverter(MediaType... supportedMediaTypes) {
        setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
    }
//对MediaType集合进行初使化
    public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
        Assert.notEmpty(supportedMediaTypes, "'supportedMediaTypes' must not be empty");
        this.supportedMediaTypes = new ArrayList<MediaType>(supportedMediaTypes);
    }

//得到支持的MediaType对象,通过Collections.unmodifiableList来防止外部进行修改
    public List<MediaType> getSupportedMediaTypes() {
        return Collections.unmodifiableList(this.supportedMediaTypes);
    }

//这里实现了canRead方法,分为了两部,一个看clazz是否支持,一个看MediaType是否支持
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return supports(clazz) && canRead(mediaType);
    }
//这里提供了canRead的默认实现
    protected boolean canRead(MediaType mediaType) {
        if (mediaType == null) {
            return true;
        }
        for (MediaType supportedMediaType : getSupportedMediaTypes()) {
            if (supportedMediaType.includes(mediaType)) {
                return true;
            }
        }
        return false;
    }

//这是canWrite方法,同样分为根据class与MediaType进行判断
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return supports(clazz) && canWrite(mediaType);
        }

//提供的默认实现
    protected boolean canWrite(MediaType mediaType) {
        if (mediaType == null || MediaType.ALL.equals(mediaType)) {
            return true;
        }
        for (MediaType supportedMediaType : getSupportedMediaTypes()) {
            if (supportedMediaType.isCompatibleWith(mediaType)) {
                return true;
            }
        }
        return false;
    }

//read方法,内部抽象了readInternal留给子类实现
    public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException {
        return readInternal(clazz, inputMessage);
    }

//write方法,首先处理需要写入header的类型与长度,并提供writeInternal方法留给子类实现,最后调用flash方法将数据写入到客户端
    public final void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {

        HttpHeaders headers = outputMessage.getHeaders();
        if (headers.getContentType() == null) {
            if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
                contentType = getDefaultContentType(t);
            }
            if (contentType != null) {
                headers.setContentType(contentType);
            }
        }
        if (headers.getContentLength() == -1) {
            Long contentLength = getContentLength(t, headers.getContentType());
            if (contentLength != null) {
                headers.setContentLength(contentLength);
            }
        }
        writeInternal(t, outputMessage);
        outputMessage.getBody().flush();
    }

//返回默认的MediaType
    protected MediaType getDefaultContentType(T t) throws IOException {
        List<MediaType> mediaTypes = getSupportedMediaTypes();
        return (!mediaTypes.isEmpty() ? mediaTypes.get(0) : null);
    }

//得到数据的长度
    protected Long getContentLength(T t, MediaType contentType) throws IOException {
        return null;
    }

//子类需要实现的方法
    protected abstract boolean supports(Class<?> clazz);

//这里实现读数据的功能
    protected abstract T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException;

//这里实现写数据的功能
    protected abstract void writeInternal(T t, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException;

}

从上面的代码分析,我们只需要关注FastJsonHttpMessageConverter类里的supports, readInternal与writeInternal方法,源码如下:

public class FastJsonHttpMessageConverter //
        extends AbstractHttpMessageConverter<Object> //
        implements GenericHttpMessageConverter<Object> {
//supports方法里可以解析任何对象
    @Override
    protected boolean supports(Class<?> clazz) {
        return true;
    }

// 这里实现将输入流转成clazz对象
    @Override
  protected Object readInternal(Class<? extends Object> clazz, //
                                  HttpInputMessage inputMessage //
    ) throws IOException, HttpMessageNotReadableException {

        InputStream in = inputMessage.getBody();
        return JSON.parseObject(in, fastJsonConfig.getCharset(), clazz, fastJsonConfig.getFeatures());
    }

//这里是写入数据的逻辑,将obj对象通过outputMessage写入,其中还会将数据的长度写入到http的头信息里
    @Override
    protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        HttpHeaders headers = outputMessage.getHeaders();
        ByteArrayOutputStream outnew = new ByteArrayOutputStream();
        int len = JSON.writeJSONString(outnew, //
                fastJsonConfig.getCharset(), //
                obj, //
                fastJsonConfig.getSerializeConfig(), //
                fastJsonConfig.getSerializeFilters(), //
                fastJsonConfig.getDateFormat(), //
                JSON.DEFAULT_GENERATE_FEATURE, //
                fastJsonConfig.getSerializerFeatures());

        if (fastJsonConfig.isWriteContentLength()) {
            headers.setContentLength(len);
        }

        OutputStream out = outputMessage.getBody();
        outnew.writeTo(out);
        outnew.close();
    }

}

  知道了HttpMessageConverter是如何进行类型转换的了,下一步就需要知道在Spring MVC里,HttpMessageConverter在那里起作用的。我们知道在Spring MVC里有两个很重要的解色,一个是HandlerMapping 用于将请求的url转到具体处理的请求Controller(Handler)上,职责为查找Handler, 另一个是 HandlerAdapter ,用于适配Handler,DispatcherServlet将不同Handler的调用职责转交给HandlerAdapter。从职责划分上我们可以很容易的猜想这是在某一个HandlerAdapter会调用的逻辑啦。我们以RequestMappingHandlerAdapter为入口来看看Spring MVC内部是如何处理类型转换的。以下是部分关键代码:

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
        InitializingBean {
//HandlerAdapter内部持有的对象
    private List<HandlerMethodArgumentResolver> customArgumentResolvers;

    private HandlerMethodArgumentResolverComposite argumentResolvers;

    private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;

    private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;

    private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

    private List<ModelAndViewResolver> modelAndViewResolvers;

    private List<HttpMessageConverter<?>> messageConverters;

//默认的构造方法,里面有我们熟悉的HttpMessageConverter对象
    public RequestMappingHandlerAdapter() {

        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
        stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316

        this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(stringHttpMessageConverter);
        this.messageConverters.add(new SourceHttpMessageConverter<Source>());
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
    }

//**
**这个方法是HandlerAdapter的核心方法, 里面有我们熟悉的ModelAndView 做为方法的返回值
**//
    @Override
    protected final ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            // Always prevent caching in case of session attribute management.
            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
        }
        else {
            // Uses configured default cacheSeconds setting.
            checkAndPrepare(request, response, true);
        }

        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    return invokeHandleMethod(request, response, handlerMethod);
                }
            }
        }
//最终会调用invokeHandleMethod方法
        return invokeHandleMethod(request, response, handlerMethod);
    }

//这个方法里会处理请求类型的转换与返回对象的转换
    private ModelAndView invokeHandleMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//这里面会处理会处理请求数据到对象的转换
        ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

        final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.setTaskExecutor(this.taskExecutor);
        asyncManager.setAsyncWebRequest(asyncWebRequest);
        asyncManager.registerCallableInterceptors(this.callableInterceptors);
        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

        if (asyncManager.hasConcurrentResult()) {
            Object result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();

            if (logger.isDebugEnabled()) {
                logger.debug("Found concurrent result value [" + result + "]");
            }
            requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
        }
//最终处理还是在这个ServletInvocableHandlerMethod对象里处理啦
        requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }

        return getModelAndView(mavContainer, modelFactory, webRequest);
    }

//这里构造了ServletInvocableHandlerMethod 对象,用于hanlder方法的调用
    private ServletInvocableHandlerMethod createRequestMappingMethod(
            HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {

        ServletInvocableHandlerMethod requestMethod;
        requestMethod = new ServletInvocableHandlerMethod(handlerMethod);
//argumentResolvers用于处理请求数据 
requestMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);

//returnValueHandlers用于处理返回数据       requestMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        requestMethod.setDataBinderFactory(binderFactory);
        requestMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        return requestMethod;
    }

//这个方法会在Spring IOC容器初使化的时候调用,里面初使化好了argumentResolvers , returnValueHandlers 对象 
    public void afterPropertiesSet() {
        if (this.argumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.initBinderArgumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.returnValueHandlers == null) {
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
        initControllerAdviceCache();
    }

//这个方法里把处理handler method方法里参数的ArgumentResolver统一放到集合对象里
    private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

        // Annotation-based argument resolution
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
        resolvers.add(new RequestParamMapMethodArgumentResolver());
//这里有我们熟悉的PathVariableMethodArgumentResolver
        resolvers.add(new PathVariableMethodArgumentResolver());
        resolvers.add(new PathVariableMapMethodArgumentResolver());
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
//这里就是我们文章开口说的@RequestBody与ResponseBody啦
        resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
        resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
        resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
        resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

        // Type-based argument resolution
        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());
        resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
        resolvers.add(new ModelMethodProcessor());
        resolvers.add(new MapMethodProcessor());
        resolvers.add(new ErrorsMethodArgumentResolver());
        resolvers.add(new SessionStatusMethodArgumentResolver());
        resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

        // Custom arguments
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }

        // Catch-all
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
        resolvers.add(new ServletModelAttributeMethodProcessor(true));

        return resolvers;
    }

//返回对象的handler
    private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();

        // Single-purpose return value types
        handlers.add(new ModelAndViewMethodReturnValueHandler());
        handlers.add(new ModelMethodProcessor());
        handlers.add(new ViewMethodReturnValueHandler());
        handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
        handlers.add(new CallableMethodReturnValueHandler());
        handlers.add(new DeferredResultMethodReturnValueHandler());
        handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

        // Annotation-based return value types
        handlers.add(new ModelAttributeMethodProcessor(false));
//这里有处理文章开头说的@RequestBody和@ResponseBody两个注释的处理逻辑
        handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));

        // Multi-purpose return value types
        handlers.add(new ViewNameMethodReturnValueHandler());
        handlers.add(new MapMethodProcessor());

        // Custom return value types
        if (getCustomReturnValueHandlers() != null) {
            handlers.addAll(getCustomReturnValueHandlers());
        }

        // Catch-all
        if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
            handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
        }
        else {
            handlers.add(new ModelAttributeMethodProcessor(true));
        }

        return handlers;
    }

}

上面对关键代码进行了相应的注释,我们从handleInternal方法跟踪到invokeHandleMethod方法里,发现最终处理请求对象与返回对象的是一个叫ServletInvocableHandlerMethod的对象,下面来看看ServletInvocableHandlerMethod的关键代码

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {

    public final void invokeAndHandle(ServletWebRequest webRequest,
            ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//invokeForRequest方法里应该就是调用逻辑了
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(this.responseReason)) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
//下面的方法会处理返回的对象,通过returnValueHandlers集合对象
        try {
            this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }

//这个方法是InvocableHandlerMethod类里的,为了方便展示我们放到这里一起注释
    public final Object invokeForRequest(NativeWebRequest request,
                                         ModelAndViewContainer mavContainer,
                                         Object... providedArgs) throws Exception {
//这里得到method里的参数
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

        if (logger.isTraceEnabled()) {
            StringBuilder builder = new StringBuilder("Invoking [");
            builder.append(this.getMethod().getName()).append("] method with arguments ");
            builder.append(Arrays.asList(args));
            logger.trace(builder.toString());
        }
//根据args调用具体的handler方法
        Object returnValue = invoke(args);

        if (logger.isTraceEnabled()) {
            logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]");
        }
//返回handler方法返回的对象
        return returnValue;
    }

//这个方法一样是InvocableHandlerMethod类里的
    private Object[] getMethodArgumentValues(
            NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
//得到方法的所有参数
        MethodParameter[] parameters = getMethodParameters();
        Object[] args = new Object[parameters.length];
//遍历方法里的每一个参数
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(parameterNameDiscoverer);
            GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());

            args[i] = resolveProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
//argumentResolvers就是上面接到的集合对象,里面存了不同的ArgumentResolver对象
            if (argumentResolvers.supportsParameter(parameter)) {
                try {
                    args[i] = argumentResolvers.resolveArgument(parameter, mavContainer, request, dataBinderFactory);
                    continue;
                } catch (Exception ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
                    }
                    throw ex;
                }
            }

            if (args[i] == null) {
                String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
                throw new IllegalStateException(msg);
            }
        }
        return args;
    }
//这里会调用HandlerMethodArgumentResolver 处理具体的方法参数
    public Object resolveArgument(
            MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
            throws Exception {

        HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
        Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
        return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    }
}

通过上面代码的分析我们可以很清晰的知道ServletInvocableHandlerMethod最终通过HandlerMethodArgumentResolvers与HandlerMethodReturnValueHandlers这两个集合对象来分别处理http请求数据到handler方法里参数的转换与返回对象转成希望输出的对象 。下面分别来看看这两个集合里存的对象都是如何处理数据的,首先是HandlerMethodArgumentResolver类的接口定义:

package org.springframework.web.method.support;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;

public interface HandlerMethodArgumentResolver {

//用于判断当前ArgumentResolver是否支持这种类型转换
    boolean supportsParameter(MethodParameter parameter);
//具体的转换方法
    Object resolveArgument(MethodParameter parameter,
                           ModelAndViewContainer mavContainer,
                           NativeWebRequest webRequest,
                           WebDataBinderFactory binderFactory) throws Exception;

}

HandlerMethodReturnValueHandler接口的定义如下:

public interface HandlerMethodReturnValueHandler {

    boolean supportsReturnType(MethodParameter returnType);

    void handleReturnValue(Object returnValue,
                           MethodParameter returnType,
                           ModelAndViewContainer mavContainer,
                           NativeWebRequest webRequest) throws Exception;

}

我们重点关注的RequestResponseBodyMethodProcessor同时继承了上面两个接口,所以他能够处理@RequestBody和@ResponseBody这两个注释啦,下面看一下关键代码:

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
//这里看参数是否有增加RequestBody注解
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestBody.class);
    }
//这里看返回的对象是否有RequestBody注解
    public boolean supportsReturnType(MethodParameter returnType) {
        return returnType.getMethodAnnotation(ResponseBody.class) != null;
    }
//这里的方法会处理请求参数的逻辑
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//通过readWithMessageConverters这个方法名我们可算看到了MessageConverter了
        Object argument = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());

        String name = Conventions.getVariableNameForParameter(parameter);
        WebDataBinder binder = binderFactory.createBinder(webRequest, argument, name);

        if (argument != null) {
            validate(binder, parameter);
        }

        mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());

        return argument;
    }

// 这个方法里应该会调用我们上面说的HttpMessageConverter
    @Override
    protected <T> Object readWithMessageConverters(NativeWebRequest webRequest,
            MethodParameter methodParam,  Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
//这里封培训HttpInputMessage对象,这个对象我们文章开头就提过了
        final HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        HttpInputMessage inputMessage = new ServletServerHttpRequest(servletRequest);

        RequestBody annot = methodParam.getParameterAnnotation(RequestBody.class);
        if (!annot.required()) {
            InputStream inputStream = inputMessage.getBody();
            if (inputStream == null) {
                return null;
            }
            else if (inputStream.markSupported()) {
                inputStream.mark(1);
                if (inputStream.read() == -1) {
                    return null;
                }
                inputStream.reset();
            }
            else {
                final PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
                int b = pushbackInputStream.read();
                if (b == -1) {
                    return null;
                }
                else {
                    pushbackInputStream.unread(b);
                }
                inputMessage = new ServletServerHttpRequest(servletRequest) {
                    @Override
                    public InputStream getBody() throws IOException {
                        // Form POST should not get here
                        return pushbackInputStream;
                    }
                };
            }
        }

        return super.readWithMessageConverters(inputMessage, methodParam, paramType);
    }

//这个方法是RequestResponseBodyMethodProcessor的父类AbstractMessageConverterMethodProcessor里的方法,为了方便看源码,我们把这个方法也放到这里注释
    @SuppressWarnings("unchecked")
    protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage,
            MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException {

                MediaType contentType = inputMessage.getHeaders().getContentType();
                if (contentType == null) {
                    contentType = MediaType.APPLICATION_OCTET_STREAM;
                }

                Class<?> contextClass = methodParam.getDeclaringClass();
                Map<TypeVariable, Type> map = GenericTypeResolver.getTypeVariableMap(contextClass);
                Class<T> targetClass = (Class<T>) GenericTypeResolver.resolveType(targetType, map);
//这里调用我们熟悉的HttpMessageConverter对象
                for (HttpMessageConverter<?> converter : this.messageConverters) {
                    if (converter instanceof GenericHttpMessageConverter) {
                        GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter;
                        if (genericConverter.canRead(targetType, contextClass, contentType)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Reading [" + targetType + "] as \"" +
                                        contentType + "\" using [" + converter + "]");
                            }
                            return genericConverter.read(targetType, contextClass, inputMessage);
                        }
                    }
                    if (targetClass != null) {
                        if (converter.canRead(targetClass, contentType)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Reading [" + targetClass.getName() + "] as \"" +
                                        contentType + "\" using [" + converter + "]");
                            }
                            return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
                        }
                    }
                }

                throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
            }
//这个方法是处理返回对象的方法了,会调用到父类里writeWithMessageConverters方法
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException {

        mavContainer.setRequestHandled(true);
        if (returnValue != null) {
            writeWithMessageConverters(returnValue, returnType, webRequest);
        }
    }
//这个方法是AbstractMessageConverterMethodProcessor类的方法,方法里分别构造了inputMessage与outputMessage对象,然后调用writeWithMessageConverters方法处理
    protected <T> void writeWithMessageConverters(T returnValue,
                                                MethodParameter returnType,
                                                NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException {
        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
    }

//这个方法也是父类AbstractMessageConverterMethodProcessor类的方法
    @SuppressWarnings("unchecked")
    protected <T> void writeWithMessageConverters(T returnValue,
                                                MethodParameter returnType,
                                                ServletServerHttpRequest inputMessage,
                                                ServletServerHttpResponse outputMessage)
            throws IOException, HttpMediaTypeNotAcceptableException {

        Class<?> returnValueClass = returnValue.getClass();

        HttpServletRequest servletRequest = inputMessage.getServletRequest();
//这里看到了熟悉的MediaType对象
        List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
        List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);

        Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
        for (MediaType r : requestedMediaTypes) {
            for (MediaType p : producibleMediaTypes) {
                if (r.isCompatibleWith(p)) {
                    compatibleMediaTypes.add(getMostSpecificMediaType(r, p));
                }
            }
        }
        if (compatibleMediaTypes.isEmpty()) {
            throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
        }

        List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
        MediaType.sortBySpecificityAndQuality(mediaTypes);

        MediaType selectedMediaType = null;
        for (MediaType mediaType : mediaTypes) {
            if (mediaType.isConcrete()) {
                selectedMediaType = mediaType;
                break;
            }
            else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
                selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
                break;
            }
        }

        if (selectedMediaType != null) {
            selectedMediaType = selectedMediaType.removeQualityValue();
//看看messageConverters里的对象那个可以处理当前对象,最终还是调用HttpMessageConverter的write方法
            for (HttpMessageConverter<?> messageConverter : messageConverters) {
                if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
                    ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +
                                messageConverter + "]");
                    }
                    return;
                }
            }
        }
        throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);
    }


}

到这里我们分析了整个的处理流程,下面我们总结一个各个对象的作用:

  • HttpMessageConverter 这个对象用于处理http请求数据到handler方法参数的转换,同时也处理handler方法返回对象输出到浏览器数据的转换。
  • HttpInputMessage用于抽象请求报文对象,可以简单理解为Servlet里的HttpRequest对象
  • HttpOutputMessage用于抽象响应报文对象,可以简单理解为Servlet里的HttpResponse对象
  • HandlerAdapter 对象是Spring MVC里最重要的对象,他对我们的handler(业务系统里写的Controller)进行了包装,这样在Spring MVC里任务对象都可以做为Controller,只要提供合适的HandlerAdapter。
  • HandlerMethodArgumentResolver 用于处理handler方法的参数转换
  • HandlerMethodReturnValueHandler 用于处理handler返回对象的转换
  • RequestResponseBodyMethodProcessor 这个同时实现了HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler内部通过注入的HttpMessageConverter集合来转换对象
    上面代码里的messageConverters是从那里来的呢,这里具体可以参考org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser这个类里的源码。此类处理了spring mvc配置文件里<mvc:annotation-driven>这个标签里的逻辑。
  • HttpMessageConverter 用于处理请求的Body部分的数据,而非Body部分的数据转换用的还是Spring Convert

使用FastJsonHttpMessageConverter踩坑

1:在用FastJsonHttpMessageConverter将json转成请求对象的时候,如果请求的类型为application/json。需要在supportedMediaTypes属性配置<value>application/json;charset=UTF-8</value>。关键配置如下:

    <mvc:annotation-driven conversion-service="conversionService">
        <mvc:message-converters register-defaults="true">
            <bean
                class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">

                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>

                <property name="features">
                    <array>
                        <value>WriteDateUseDateFormat</value>
                        <value>WriteMapNullValue</value>
                        <value>WriteNullStringAsEmpty</value>
                    </array>
                </property>

            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

注意上面的mvc:message-converters是用于将http请求的body对象进行转换的。而conversion-service="conversionService"会对如通过URL,Header,对象进行转换,这是两套不同的转换体系。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,306评论 1 92
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • Spring MVC一、什么是 Spring MVCSpring MVC 属于 SpringFrameWork 的...
    任任任任师艳阅读 3,372评论 0 32
  • Y小姐是漂亮的,至少在我眼中是这样的,但是Y小姐也是神秘的,或许是与Y小姐接触不多,也可能是Y小姐本来就是那样的“...
    忆过去往事阅读 1,173评论 0 0