Spring 源码解析十:请求参数注解解析器与响应值注解处理器

x33g5p2x  于2022-02-11 发布在 Spring  
字(17.2k)|赞(0)|评价(0)|浏览(291)

在 Spring 源码解析六:处理器映射与处理器适配处理 中,有一些请求参数默认的注解解析器与响应值默认的注解处理器还未解析

请求参数默认的注解解析器主要是:

响应值默认的注解处理器主要是:

下面我们选一些典型的来解析

1. RequestParamMethodArgumentResolver

RequestParamMethodArgumentResolver
的主要功能是解析 @RequestParam

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
        implements UriComponentsContributor {}

先来看看 AbstractNamedValueMethodArgumentResolver

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
    // 解析参数
    @Override
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        // 获取名称值信息
        NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);

        // 如果名字里有表达式,解析表达式
        Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);

        // 解析名称对应的值,由子类实现
        Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);

        // 如果没有值
        if (arg == null) {
            // 有defaultValue的话,解析defaultValue的表达式,并使用默认值
            if (namedValueInfo.defaultValue != null) {
                arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
            }

            // ... 代码省略
        }

        // ... 代码省略

        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
            try {
                // 转换值String类型到目标类型
                arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
            }
            catch (ConversionNotSupportedException ex) {
                // ... 代码省略
            }

            // ... 代码省略
        }

        // 后置处理,由子类实现
        handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

        return arg;
    }
}

再来看看 RequestParamMethodArgumentResolver

public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
        implements UriComponentsContributor {
    // 解析名字
    @Override
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
        // 获取原生的HttpServletRequest
        HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);

        // ... 代码省略

        Object arg = null;
        MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
        // 文件上传处理
        if (multipartRequest != null) {
            List<MultipartFile> files = multipartRequest.getFiles(name);
            if (!files.isEmpty()) {
                arg = (files.size() == 1 ? files.get(0) : files);
            }
        }
        // 获取参数值
        if (arg == null) {
            String[] paramValues = request.getParameterValues(name);
            if (paramValues != null) {
                arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
            }
        }
        return arg;
    }

}

2. RequestParamMapMethodArgumentResolver

RequestParamMapMethodArgumentResolver
的主要功能是解析 @RequestParam,但不指定参数名字,返回整个参数 Map

public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
    // 解析参数
    @Override
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        // MultiValueMap
        if (MultiValueMap.class.isAssignableFrom(parameter.getParameterType())) {
            Class<?> valueType = resolvableType.as(MultiValueMap.class).getGeneric(1).resolve();

            // 文件上传
            if (valueType == MultipartFile.class) {
                // ... 代码省略
            }
            // 单片文件上传
            else if (valueType == Part.class) {
                // ... 代码省略
            }
            // 普通字符
            else {
                Map<String, String[]> parameterMap = webRequest.getParameterMap();
                MultiValueMap<String, String> result = new LinkedMultiValueMap<>(parameterMap.size());
                parameterMap.forEach((key, values) -> {
                    for (String value : values) {
                        result.add(key, value);
                    }
                });
                return result;
            }
        }
        // 普通Map
        else {
            Class<?> valueType = resolvableType.asMap().getGeneric(1).resolve();

            // 文件上传
            if (valueType == MultipartFile.class) {
                // ... 代码省略
            }
            // 单片文件上传
            else if (valueType == Part.class) {
                // ... 代码省略
            }
            // 普通字符
            else {
                Map<String, String[]> parameterMap = webRequest.getParameterMap();
                Map<String, String> result = CollectionUtils.newLinkedHashMap(parameterMap.size());
                parameterMap.forEach((key, values) -> {
                    if (values.length > 0) {
                        result.put(key, values[0]);
                    }
                });
                return result;
            }
        }
    }
}

3. PathVariableMethodArgumentResolver

PathVariableMethodArgumentResolver
的主要功能是解析 @PathVariable

public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
        implements UriComponentsContributor {
    // 解析名字
    @Override
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
        // 获取解析好的Map
        Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(
                HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
        // 从Map中取
        return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);
    }
}

4. RequestResponseBodyMethodProcessor

RequestResponseBodyMethodProcessor
的主要功能是处理 @RequestBody@ResponseBody

先来看看继承关系

- AbstractMessageConverterMethodArgumentResolver
  - AbstractMessageConverterMethodProcessor
    - RequestResponseBodyMethodProcessor

4.1. AbstractMessageConverterMethodArgumentResolver

AbstractMessageConverterMethodArgumentResolver
的主要功能是可以使用消息转换器把输入转换成需要的对象

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
    // 使用消息转换器把请求体读取为对象
    protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
            Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
        // ... 代码省略

        // 获取转换到目标对象的类
        Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
        if (targetClass == null) {
            ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
            targetClass = (Class<T>) resolvableType.resolve();
        }

        // ... 代码省略

        Object body = NO_VALUE;

        EmptyBodyCheckingHttpInputMessage message;
        try {
            // 初始化一个输入流读取器
            message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
            // 遍历转换器
            for (HttpMessageConverter<?> converter : this.messageConverters) {
                // 转换类型
                Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
                // 是否是GenericHttpMessageConverter
                GenericHttpMessageConverter<?> genericConverter =
                        (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
                // 读取请求体,处理
                if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
                        (targetClass != null && converter.canRead(targetClass, contentType))) {
                    if (message.hasBody()) {
                        // 读取前处理
                        HttpInputMessage msgToUse =
                                getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
                        // 读取请求体
                        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) {
            // ... 代码省略
        }

        // ... 代码省略

        return body;
    }
}

4.2. AbstractMessageConverterMethodProcessor

AbstractMessageConverterMethodProcessor
的主要功能是可以使用消息转换器把响应对象转换成输出

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
        implements HandlerMethodReturnValueHandler {
    // 转换对象为输出
    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 (isResourceType(value, returnType)) {
            outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
            if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&
                    outputMessage.getServletResponse().getStatus() == 200) {
                Resource resource = (Resource) value;
                try {
                    List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
                    outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());
                    body = HttpRange.toResourceRegions(httpRanges, resource);
                    valueType = body.getClass();
                    targetType = RESOURCE_REGION_LIST_TYPE;
                }
                catch (IllegalArgumentException ex) {
                    // ... 代码省略
                }
            }
        }

        MediaType selectedMediaType = null;
        // 输出内容类型content-type
        MediaType contentType = outputMessage.getHeaders().getContentType();
        // 有内容类型
        boolean isContentTypePreset = contentType != null && contentType.isConcrete();
        if (isContentTypePreset) {
            selectedMediaType = contentType;
        }
        else {
            // ... 代码省略,如果没有内容类型,就从内容判断
        }

        // 遍历消息转换器
        for (HttpMessageConverter<?> converter : this.messageConverters) {
            // 是否是GenericHttpMessageConverter
            GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
                    (GenericHttpMessageConverter<?>) converter : null);
            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) {
                    // 添加Content-Disposition头
                    addContentDispositionHeader(inputMessage, outputMessage);
                    // 把body转换并输出到outputMessage
                    if (genericConverter != null) {
                        genericConverter.write(body, targetType, selectedMediaType, outputMessage);
                    }
                    else {
                        ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
                    }
                }
                return;
            }
        }

        // ... 代码省略
    }
}

4.3. RequestResponseBodyMethodProcessor

RequestResponseBodyMethodProcessor
的主要功能是输入与输出都可以使用消息转换器转换

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    // 解析参数
    @Override
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        // 使用消息转换器把请求体读取为对象
        Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
        // 变量名
        String name = Conventions.getVariableNameForParameter(parameter);

        // 有数据绑定工厂
        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {
                // 如果有@Validated的注解,则需要验证
                validateIfApplicable(binder, parameter);

                // ... 代码省略
            }

            // ... 代码省略
        }

        // 适配一下Optional
        return adaptArgumentIfNecessary(arg, parameter);
    }

    // 使用消息转换器把请求体读取为对象
    @Override
    protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
            Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
        // 获取原始的请求对象
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);

        // 使用父类的方法转换
        Object arg = readWithMessageConverters(inputMessage, parameter, paramType);

        // ... 代码省略

        return arg;
    }
}
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    // 处理响应值
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

        // 使用父类的方法转换对象为输出
        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
    }
}

5. HttpEntityMethodProcessor

HttpEntityMethodProcessor
的主要功能是处理 HttpEntity

public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor {
    // 解析名字
    @Override
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)
            throws IOException, HttpMediaTypeNotSupportedException {

        // 创建ServletServerHttpRequest
        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        // 获取数据类型
        Type paramType = getHttpEntityType(parameter);

        // 使用消息转换器把请求体读取为对象
        Object body = readWithMessageConverters(webRequest, parameter, paramType);

        // 如果RequestEntity类型,封装为RequestEntity,不然就是普通的HttpEntity
        if (RequestEntity.class == parameter.getParameterType()) {
            return new RequestEntity<>(body, inputMessage.getHeaders(),
                    inputMessage.getMethod(), inputMessage.getURI());
        }
        else {
            return new HttpEntity<>(body, inputMessage.getHeaders());
        }
    }
}
public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor {
    // 处理响应值
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        // ... 代码省略

        // 创建输入输出消息对象
        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

        HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue;

        // 获取输出消息头
        HttpHeaders outputHeaders = outputMessage.getHeaders();
        HttpHeaders entityHeaders = responseEntity.getHeaders();

        // ... 代码省略,把entityHeaders载入outputHeaders

        if (responseEntity instanceof ResponseEntity) {
            // ... 代码省略,如果是 get/head 方法,并且是200状态码,直接输入
        }

        // 使用父类的方法转换对象为输出
        writeWithMessageConverters(responseEntity.getBody(), returnType, inputMessage, outputMessage);

        // ... 代码省略
    }
}

6. ModelAndViewMethodReturnValueHandler

ModelAndViewMethodReturnValueHandler
的主要功能是输出 ModelAndView

public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
    // 处理响应值
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        // 没有响应值,直接返回
        if (returnValue == null) {
            mavContainer.setRequestHandled(true);
            return;
        }

        ModelAndView mav = (ModelAndView) returnValue;
        // 是viewName
        if (mav.isReference()) {
            String viewName = mav.getViewName();
            mavContainer.setViewName(viewName);
            if (viewName != null && isRedirectViewName(viewName)) {
                mavContainer.setRedirectModelScenario(true);
            }
        }
        // 是view对象
        else {
            View view = mav.getView();
            mavContainer.setView(view);
            if (view instanceof SmartView && ((SmartView) view).isRedirectView()) {
                mavContainer.setRedirectModelScenario(true);
            }
        }
        mavContainer.setStatus(mav.getStatus());
        mavContainer.addAllAttributes(mav.getModel());
    }
}

7. StreamingResponseBodyReturnValueHandler

StreamingResponseBodyReturnValueHandler
的主要功能是输出 StreamingResponseBody

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {
    // 处理响应值
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        // 没有响应值,直接返回
        if (returnValue == null) {
            mavContainer.setRequestHandled(true);
            return;
        }

        // 获取原始输出
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

        ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);

        // 如果是ResponseEntity,并且有响应体,直接输出
        if (returnValue instanceof ResponseEntity) {
            ResponseEntity<?> responseEntity = (ResponseEntity<?>) returnValue;
            response.setStatus(responseEntity.getStatusCodeValue());
            outputMessage.getHeaders().putAll(responseEntity.getHeaders());
            returnValue = responseEntity.getBody();
            if (returnValue == null) {
                mavContainer.setRequestHandled(true);
                outputMessage.flush();
                return;
            }
        }

        StreamingResponseBody streamingBody = (StreamingResponseBody) returnValue;

        Callable<Void> callable = new StreamingResponseBodyTask(outputMessage.getBody(), streamingBody);
        // 异步输出
        WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
    }
}

8. ViewNameMethodReturnValueHandler

ViewNameMethodReturnValueHandler
的主要功能是输出视图名字

public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
    // 处理响应值
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

        if (returnValue instanceof CharSequence) {
            String viewName = returnValue.toString();
            mavContainer.setViewName(viewName);
            if (isRedirectViewName(viewName)) {
                mavContainer.setRedirectModelScenario(true);
            }
        }
        else if (returnValue != null) {
            // should not happen
            throw new UnsupportedOperationException("Unexpected return type: " +
                    returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
        }
    }
}

后续

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证

相关文章