SpringMVC @ResponseBody处理流程

来源:互联网 发布:autodesk公司的软件 编辑:程序博客网 时间:2024/06/06 12:57

SpringMVC的Controller方法的返回值大体有两种:
1. ModelAndView(没有使用@ResponseBody注解)
2. 直接输出到响应流的数据(使用@ResponseBody注解,没有视图解析的步骤)

/** * 指示方法返回值直接绑定到 HTTP Response Body 的注解 */@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ResponseBody {}

@ResponseBody注解的处理类org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor

    @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);        // Try even with null return value. ResponseBodyAdvice could get involved.        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);    }

SpringMVC是如何找到该处理器的:

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {    //...    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;    }    //...}

RequestResponseBodyMethodProcessor的supportsReturnType方法为:

@Override    public boolean supportsReturnType(MethodParameter returnType) {        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||                returnType.hasMethodAnnotation(ResponseBody.class));    }    //第一个在类上查找该注解,第二个在方法上查找该注解

因为我们使用了@ResponseBody 注解,所以以上方法返回true
HandlerMethodReturnValueHandlerComposite可以认为是HandlerMethodReturnValueHandler的包装器类。

我们知道RequestMappingHandlerAdapter是处理请求的适配器,也就是请求之后处理具体逻辑的执行,关系到哪个类的哪个方法以及转换器等工作。
RequestMappingHandlerAdapter在进行handle的时候,会委托给HandlerMethod(具体由子类ServletInvocableHandlerMethod处理)的invokeAndHandle方法进行处理,这个方法又转接给HandlerMethodReturnValueHandlerComposite处理。

RequestResponseBodyMethodProcessor继承自org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor

@ResponseBody 的真正处理程序在AbstractMessageConverterMethodProcessor 里的writeWithMessageConverters

    protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,            ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {        Object outputValue;        Class<?> valueType;        Type declaredType;        if (value instanceof CharSequence) {            outputValue = value.toString();            valueType = String.class;            declaredType = String.class;        }        else {            outputValue = value;            valueType = getReturnValueType(outputValue, returnType);            declaredType = getGenericType(returnType);        }        if (isResourceType(value, returnType)) {            outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");            if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null) {                Resource resource = (Resource) value;                try {                    List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();                    outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());                    outputValue = HttpRange.toResourceRegions(httpRanges, resource);                    valueType = outputValue.getClass();                    declaredType = RESOURCE_REGION_LIST_TYPE;                }                catch (IllegalArgumentException ex) {                    outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());                    outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());                }            }        }        HttpServletRequest request = inputMessage.getServletRequest();        List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);        List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);        if (outputValue != null && producibleMediaTypes.isEmpty()) {            throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);        }        Set<MediaType> compatibleMediaTypes = new LinkedHashSet<>();        for (MediaType requestedType : requestedMediaTypes) {            for (MediaType producibleType : producibleMediaTypes) {                if (requestedType.isCompatibleWith(producibleType)) {                    compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));                }            }        }        if (compatibleMediaTypes.isEmpty()) {            if (outputValue != null) {                throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);            }            return;        }        List<MediaType> mediaTypes = new ArrayList<>(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();            for (HttpMessageConverter<?> converter : this.messageConverters) {                GenericHttpMessageConverter genericConverter =                        (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);                if (genericConverter != null ?                        ((GenericHttpMessageConverter) converter).canWrite(declaredType, valueType, selectedMediaType) :                        converter.canWrite(valueType, selectedMediaType)) {                    outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,                            (Class<? extends HttpMessageConverter<?>>) converter.getClass(),                            inputMessage, outputMessage);                    if (outputValue != null) {                        addContentDispositionHeader(inputMessage, outputMessage);                        if (genericConverter != null) {                            genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage);                        }                        else {                            ((HttpMessageConverter) converter).write(outputValue, selectedMediaType, outputMessage);                        }                        if (logger.isDebugEnabled()) {                            logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +                                    "\" using [" + converter + "]");                        }                    }                    return;                }            }        }        if (outputValue != null) {            throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);        }    }
    private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException {        List<MediaType> mediaTypes = this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));        return (mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes);    }

获得请求信息头里的Accept属性,如果为空则返回*/*

    protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass,            @Nullable Type declaredType) {        Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);        if (!CollectionUtils.isEmpty(mediaTypes)) {            return new ArrayList<>(mediaTypes);        }        else if (!this.allSupportedMediaTypes.isEmpty()) {            List<MediaType> result = new ArrayList<>();            for (HttpMessageConverter<?> converter : this.messageConverters) {                if (converter instanceof GenericHttpMessageConverter && declaredType != null) {                    if (((GenericHttpMessageConverter<?>) converter).canWrite(declaredType, valueClass, null)) {                        result.addAll(converter.getSupportedMediaTypes());                    }                }                else if (converter.canWrite(valueClass, null)) {                    result.addAll(converter.getSupportedMediaTypes());                }            }            return result;        }        else {            return Collections.singletonList(MediaType.ALL);        }    }

this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters);

    private static List<MediaType> getAllSupportedMediaTypes(List<HttpMessageConverter<?>> messageConverters) {        Set<MediaType> allSupportedMediaTypes = new LinkedHashSet<>();        for (HttpMessageConverter<?> messageConverter : messageConverters) {            allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());        }        List<MediaType> result = new ArrayList<>(allSupportedMediaTypes);        MediaType.sortBySpecificity(result);        return Collections.unmodifiableList(result);    }

allSupportedMediaTypes 保存了容器内所有的HttpMessageConverter 支持的媒体类型

List<MediaType> requestedMediaTypes 保存了客户端需要的哪一种类型的数据(Accept)。
List<MediaType> producibleMediaTypes 也即保存了该容器可以产生的 Content-Type 类型的数据。
哪一个HttpMessageConverter可以处理你的Controller方法返回的对象,则把该HttpMessageConverter支持的媒体类型返回。

writeWithMessageConverters 方法的作用也就是选择合适的HttpMessageConverter,按照合适的 MediaType ,把数据写入到输出流。

这里写图片描述

参考:
https://my.oschina.net/lichhao/blog/172562
http://www.cnblogs.com/fangjian0423/p/springMVC-xml-json-convert.html
http://blog.csdn.net/fw0124/article/details/48280083

原创粉丝点击