前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入分析Spring MVC中RequestBody与ResponseBody

深入分析Spring MVC中RequestBody与ResponseBody

作者头像
良辰美景TT
发布2018-09-11 14:25:41
2.1K0
发布2018-09-11 14:25:41
举报

  在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换。在Spring MVC内部是如何做到的呢?先记住下面这张图,然后对里面的每个对象进行分析:

  • HttpInputMessage HttpInputMessage是对一次Http请求报文的抽象。接口定义了getBody方法用于得到http请求的InputStream对象。具体的接口定义如下:
代码语言:javascript
复制
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对象。源码如下:
代码语言:javascript
复制
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 对消息转换器最高层次的接口抽象,描述了一个消息转换器的一般特征。源代码如下:
代码语言:javascript
复制
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的逻辑,代码如下:

代码语言:javascript
复制
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方法,源码如下:

代码语言:javascript
复制
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内部是如何处理类型转换的。以下是部分关键代码:

代码语言:javascript
复制
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的关键代码

代码语言:javascript
复制
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类的接口定义:

代码语言:javascript
复制
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接口的定义如下:

代码语言:javascript
复制
public interface HandlerMethodReturnValueHandler {

    boolean supportsReturnType(MethodParameter returnType);

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

}

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

代码语言:javascript
复制
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>。关键配置如下:

代码语言:javascript
复制
    <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,对象进行转换,这是两套不同的转换体系。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.07.25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用FastJsonHttpMessageConverter踩坑
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档