当前位置: 首页 > news >正文

Spring 源码学习(十五)—— HandlerMethodReturnValueHandler

        HandlerMethodReturnValueHandler 对象用于请求处理方法结果的解析。其拥有 2 个方法,分别为判断是否支持指定 MethodParameter 返回参数的 supportsReturnType 方法与 handleReturnValue 返回值处理方法。

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

1 HandlerMethodReturnValueHandlerComposite

        与 HandlerMethodArgumentResolver 接口的实现一样,HandlerMethodReturnValueHandler 也拥有一个复合返回值处理器(HandlerMethodReturnValueHandlerComposite ),只用于返回值处理器的保存及结果处理器路由而不提供具体的结果处理逻辑。

1.1 变量

        HandlerMethodReturnValueHandlerComposite 类只有一个 HandlerMethodReturnValueHandler 列表变量 returnValueHandlers,用于保存其可使用的所有处理器。

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();public List<HandlerMethodReturnValueHandler> getHandlers() {return Collections.unmodifiableList(this.returnValueHandlers);}public HandlerMethodReturnValueHandlerComposite addHandler(HandlerMethodReturnValueHandler handler) {this.returnValueHandlers.add(handler);return this;}public HandlerMethodReturnValueHandlerComposite addHandlers(@Nullable List<? extends HandlerMethodReturnValueHandler> handlers) {if (handlers != null) {this.returnValueHandlers.addAll(handlers);}return this;}
}

1.2 方法

1.2.1 supportsReturnType 方法

        supportsReturnType 方法直接返回 returnValueHandlers 中是否存在指定 returnType 的处理器。

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {@Overridepublic boolean supportsReturnType(MethodParameter returnType) {return getReturnValueHandler(returnType) != null;}@Nullableprivate HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {if (handler.supportsReturnType(returnType)) {return handler;}}return null;}
}

1.2.2 handleReturnValue 方法

        handleReturnValue 方法首先通过 selectHandler 方法获取对应的返回值处理,然后调用处理器的 handleReturnValue 方法处理返回结果。

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {@Overridepublic 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);}
}

        selectHandler 方法首先通过 isAsyncReturnValue 方法判断是否为异步返回值,随后遍历 returnValueHandlers 列表获取适配的处理器并返回。

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {@Nullableprivate 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;}private boolean isAsyncReturnValue(@Nullable Object value, MethodParameter returnType) {for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {if (handler instanceof AsyncHandlerMethodReturnValueHandler &&((AsyncHandlerMethodReturnValueHandler) handler).isAsyncReturnValue(value, returnType)) {return true;}}return false;}
}

2 RequestResponseBodyMethodProcessor 类

        RequestResponseBodyMethodProcessor 类用于 RequestBody 请求值与 ResponseBody 返回值的处理,由于在之前HandlerMethodArgumentResolver 方法处理器分析已分析过 RequestBody 请求参数处理,因此本文就对 HandlerMethodReturnValueHandler 接口实现进行分析。

2.0 handleReturnValue 方法概览

2.1  AbstractMessageConverterMethodProcessor 抽象类

2.1.1 变量

  • 常量

        AbstractMessageConverterMethodProcessor 拥有 4 个常量:SAFE_EXTENSIONS 为安全的文件扩展名(通常不会被服务器端执行、可以直接提供给客户端下载及不会造成如 XSS、代码注入等的安全风险);SAFE_MEDIA_BASE_TYPES 为安全的媒体类型主类型(通常是二进制内容,不会在浏览器中作为 HTML 执行、不会导致脚本注入攻击及安全地作为附件下载);ALL_APPLICATION_MEDIA_TYPES 为表示所有应用相关的媒体类型,主要用于内容协商、HTTP 范围请求处理及响应类型匹配;最后一个常量则是资源区域列表类型 RESOURCE_REGION_LIST_TYPE,用于 HTTP 范围请求(Range Requests),支持视频/音频的断点续传、大文件的分块下载及部分内容传输(HTTP 206 Partial Content)。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {private static final Set<String> SAFE_EXTENSIONS = new HashSet<>(Arrays.asList("txt", "text", "yml", "properties", "csv","json", "xml", "atom", "rss","png", "jpe", "jpeg", "jpg", "gif", "wbmp", "bmp"));private static final Set<String> SAFE_MEDIA_BASE_TYPES = new HashSet<>(Arrays.asList("audio", "image", "video"));private static final List<MediaType> ALL_APPLICATION_MEDIA_TYPES =Arrays.asList(MediaType.ALL, new MediaType("application"));private static final Type RESOURCE_REGION_LIST_TYPE =new ParameterizedTypeReference<List<ResourceRegion>>() { }.getType();
}
  • 类变量

        AbstractMessageConverterMethodProcessor 类有两个类变量,分别为 contentNegotiationManager(内容协商控制器)与 safeExtensions(安全扩展名列表)。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {private final ContentNegotiationManager contentNegotiationManager;private final Set<String> safeExtensions = new HashSet<>();
}

2.1.2 方法

  • 构造方法

        AbstractMessageConverterMethodProcessor 虽有三个构造方法,但实际都是调用第三个构造方法,其拥有三个参数:消息转换器列表(converters)、内容协商控制器(manager)及请求响应体切面列表(requestResponseBodyAdvice)。其首先使用 converters 与 requestResponseBodyAdvice 调用父类对应构造方法,随后在 manager 参数不为空时将其保存至 contentNegotiationManager 属性之中,否则将 contentNegotiationManager 属性初始化为新建的 ContentNegotiationManager 对象;之后依次向 safeExtensions 属性中添加 contentNegotiationManager 控制器中的所有文章扩展名及 SAFE_EXTENSIONS 常量值。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters) {this(converters, null, null);}protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters,@Nullable ContentNegotiationManager contentNegotiationManager) {this(converters, contentNegotiationManager, null);}protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters,@Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) {super(converters, requestResponseBodyAdvice);this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());this.safeExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());this.safeExtensions.addAll(SAFE_EXTENSIONS);}
}
  • createOutputMessage 方法

        createOutputMessage 方法用于构建 ServletServerHttpResponse 响应对象用于输出消息。其首先尝试将 webRequest 中的响应转化为 HttpServletResponse 对象,转换失败则直接抛出异常,否则使用 ServletServerHttpResponse 对响应进行封装并返回。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequest) {HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);Assert.state(response != null, "No HttpServletResponse");return new ServletServerHttpResponse(response);}
}
  •  writeWithMessageConverters 方法

        writeWithMessageConverters 方法选择合适的消息转换器输出响应结果。在请求参数为 NativeWebRequest 对象时,依次通过 createInputMessage 与 createOutputMessage 方法创建 ServletServerHttpRequest 与 ServletServerHttpResponse 对象之后调用另一个 writeWithMessageConverters 方法进行实际数据输出。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {ServletServerHttpRequest inputMessage = createInputMessage(webRequest);ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);writeWithMessageConverters(value, returnType, inputMessage, outputMessage);}
}

        writeWithMessageConverters 方法在 value 为字符串序列时将其转换为字符串后保存到 body 变量,同时将 valueType 与 targetType 更新为 String 类对象;否则直接将 value 保存至 body 变量,并返回依次调用 getReturnValueType 与 getGenericType 方法来为 valueType 与 targetType 变量赋值。之后若返回值为资源 Resource 类型,首先将 ACCEPT_RANGES 响应头设置为 bytes,表明响应支持字节范围请求,在 value 不为 null、拥有 RANGE 请求头及响应状态为 200(未被处理)时,首先获取请求的所有 RANGE 请求头并将响应状态设置 206 表明当前为部分内容响应,并通过 HttpRange 的 toResourceRegions 方法获取指定范围内的字节数据并保存到 body 变量之中,最后依次将 valueType 与 targetType 变量更新为 body 参数对应类型与 RESOURCE_REGION_LIST_TYPE 常量值。

        之后若拥有具体响应类型,则会将该类型更新到 selectedMediaType 变量,否则将会通过 getAcceptableMediaTypes 与 getProducibleMediaTypes 获取请求需要媒体类型与响应支持类型列表并分别保存至 acceptableTypes 与 producibleTypes 变量之中,在 body 不为空且 producibleTypes 变量为空时,直接抛出 HttpMessageNotWritableException 异常;之后通过 getMostSpecificMediaType 方法将 acceptableTypes 与 producibleTypes 中的更具体类型保存至 mediaTypesToUse 变量之中,若未获取到任何媒体类型但 body 不为空则会抛出异常,body 为空则是直接返回;最后变量排序后 mediaTypesToUse 中的所有媒体类型,将其中第一个具体媒体类型保存至 selectedMediaType 或第一个应用类型回退至 APPLICATION_OCTET_STREAM 字节流媒体类型保存至 selectedMediaType 变量。

        然后在 selectedMediaType 不为空时,利用其与 valueType 返回值类型及 targetType 目标类型获取第一个匹配的 GenericHttpMessageConverter 消息转换器,并调用请求响应切面链的 beforeBodyWrite 方法对响应结果进行写前处理并将其结果更新到 body 变量之中;并在 body 不为空时,首先调用 addContentDispositionHeader 方法在必要时添加 CONTENT_DISPOSITION 响应头,并在之后消息转换器的 wirte 方法向响应中写入响应体内容并返回。

        最后再没找到对应的消息解析器但 body 不为空时抛出对应异常。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {@SuppressWarnings({"rawtypes", "unchecked"})protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {Object body;Class<?> valueType;Type targetType;if (value instanceof CharSequence) {body = value.toString();valueType = String.class;targetType = String.class;}else {body = value;valueType = getReturnValueType(body, returnType);targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());}if (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) {outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());}}}MediaType selectedMediaType = null;MediaType contentType = outputMessage.getHeaders().getContentType();boolean isContentTypePreset = contentType != null && contentType.isConcrete();if (isContentTypePreset) {if (logger.isDebugEnabled()) {logger.debug("Found 'Content-Type:" + contentType + "' in response");}selectedMediaType = contentType;}else {HttpServletRequest request = inputMessage.getServletRequest();List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);if (body != null && producibleTypes.isEmpty()) {throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);}List<MediaType> mediaTypesToUse = new ArrayList<>();for (MediaType requestedType : acceptableTypes) {for (MediaType producibleType : producibleTypes) {if (requestedType.isCompatibleWith(producibleType)) {mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));}}}if (mediaTypesToUse.isEmpty()) {if (body != null) {throw new HttpMediaTypeNotAcceptableException(producibleTypes);}if (logger.isDebugEnabled()) {logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);}return;}MediaType.sortBySpecificityAndQuality(mediaTypesToUse);for (MediaType mediaType : mediaTypesToUse) {if (mediaType.isConcrete()) {selectedMediaType = mediaType;break;}else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;break;}}if (logger.isDebugEnabled()) {logger.debug("Using '" + selectedMediaType + "', given " +acceptableTypes + " and supported " + producibleTypes);}}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(targetType, valueType, selectedMediaType) :converter.canWrite(valueType, selectedMediaType)) {body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) converter.getClass(),inputMessage, outputMessage);if (body != null) {Object theBody = body;LogFormatUtils.traceDebug(logger, traceOn ->"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");addContentDispositionHeader(inputMessage, outputMessage);if (genericConverter != null) {genericConverter.write(body, targetType, selectedMediaType, outputMessage);}else {((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);}}else {if (logger.isDebugEnabled()) {logger.debug("Nothing to write: null body");}}return;}}}if (body != null) {Set<MediaType> producibleMediaTypes =(Set<MediaType>) inputMessage.getServletRequest().getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {throw new HttpMessageNotWritableException("No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");}throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);}}
}

        getReturnValueType 方法在 value 不为空时直接返回其对应 Class 类对象,否则返回 returnType 的 getParameterType 方法获取到的返回参数类型。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {protected Class<?> getReturnValueType(@Nullable Object value, MethodParameter returnType) {return (value != null ? value.getClass() : returnType.getParameterType());}
}

        getGenericType 方法用于获取返回参数实际泛型类型。值得注意的是其不是直接获取的返回值泛型,在为 HttpEntity 对象时会获取 HttpEntity 泛型对象中的实际泛型,其他情况则是获取返回值反省。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {private Type getGenericType(MethodParameter returnType) {if (HttpEntity.class.isAssignableFrom(returnType.getParameterType())) {return ResolvableType.forType(returnType.getGenericParameterType()).getGeneric().getType();}else {return returnType.getGenericParameterType();}}
}

        isResourceType 方法用于判断返回值是否为资源,其首先通过 getReturnValueType 方法获取返回值类型并返回其是否为 Resource 但不为 InputStreamResource 对象。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {protected boolean isResourceType(@Nullable Object value, MethodParameter returnType) {Class<?> clazz = getReturnValueType(value, returnType);return clazz != InputStreamResource.class && Resource.class.isAssignableFrom(clazz);}
}

        getAcceptableMediaTypes 方法用于获取当前请求需要的媒体类型。其调用 contentNegotiationManager 的 resolveMediaTypes 方法获取需要的媒体类型并返回。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request)throws HttpMediaTypeNotAcceptableException {return this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));}
}

        getProducibleMediaTypes 方法则用于获取响应提供的媒体类型。其首先尝试从请求的 PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE 属性中获取之前 RequestMappingInfoHandlerMapping 的 handleMatch 方法中解析从处理器方法中获取的媒体类型列表,在其不为空时直接返回该列表值,否则在 allSupportedMediaTypes 参数为空时直接返回 MediaType.ALL 单元素数组(messageConverters 属性中的所有转换器可能都支持所有媒体类型)。在其它情况下则会从 messageConverters 属性中获取支持当前返回值的转换器并将其对应媒体类型保存至 result 属性中并返回。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, @Nullable Type targetType) {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 && targetType != null) {if (((GenericHttpMessageConverter<?>) converter).canWrite(targetType, valueClass, null)) {result.addAll(converter.getSupportedMediaTypes());}}else if (converter.canWrite(valueClass, null)) {result.addAll(converter.getSupportedMediaTypes());}}return result;}else {return Collections.singletonList(MediaType.ALL);}}
}

        getMostSpecificMediaType 方法用于获取 acceptType 与 produceType 中特异值更多(更具体)的媒体类型,其是通过 MediaType 的 SPECIFICITY_COMPARATOR 比较器常量对象进行对比的,注意为了消除质量值(q参数)对特异值比较的影响,其首先通过 copyQualityValue 方法将 acceptType 的参数值复制到 produceType 参数之中。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) {MediaType produceTypeToUse = produceType.copyQualityValue(acceptType);return (MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceTypeToUse) <= 0 ? acceptType : produceTypeToUse);}
}

         getMostSpecificMediaType 方法用于获取 acceptType 与 produceType 中特异值更多(更具体)的媒体类型,其是通过 MediaType 的 SPECIFICITY_COMPARATOR 比较器常量对象进行对比的,注意为了消除质量值(q参数)对特异值比较的影响,其首先通过 copyQualityValue 方法将 acceptType 的参数值复制到 produceType 参数之中。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) {MediaType produceTypeToUse = produceType.copyQualityValue(acceptType);return (MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceTypeToUse) <= 0 ? acceptType : produceTypeToUse);}
}

        addContentDispositionHeader 方法用于设置 CONTENT_DISPOSITION 响应头(目的是在处理文件下载或显示时,根据请求的URI和文件扩展名来判断是否安全),其在已设置了 CONTENT_DISPOSITION 响应头或响应状态为 200 以下(信息状态码)或大于 299 且小于 400 时(重定向)直接返回。之后将请求路径最后一个 / 之后的字符串使用第一个 ; 进行分割,; 之前的元素保存至 filename 变量作为是文件名,之后的字符串保存至 pathParams 参数作为路径参数并解析获取对应的文件扩展名分别保存至 ext 与 extInPathParams 变量之中。之后通过 safeExtension 方法依次验证 ext 与 extInPathParams 两个扩展名值是否安全,若存在不安全扩展名则会向添加 CONTENT_DISPOSITION 与 inline;filename=f.txt 作为响应头。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {private void addContentDispositionHeader(ServletServerHttpRequest request, ServletServerHttpResponse response) {HttpHeaders headers = response.getHeaders();if (headers.containsKey(HttpHeaders.CONTENT_DISPOSITION)) {return;}try {int status = response.getServletResponse().getStatus();if (status < 200 || (status > 299 && status < 400)) {return;}}catch (Throwable ex) {// ignore}HttpServletRequest servletRequest = request.getServletRequest();String requestUri = UrlPathHelper.rawPathInstance.getOriginatingRequestUri(servletRequest);int index = requestUri.lastIndexOf('/') + 1;String filename = requestUri.substring(index);String pathParams = "";index = filename.indexOf(';');if (index != -1) {pathParams = filename.substring(index);filename = filename.substring(0, index);}filename = UrlPathHelper.defaultInstance.decodeRequestString(servletRequest, filename);String ext = StringUtils.getFilenameExtension(filename);pathParams = UrlPathHelper.defaultInstance.decodeRequestString(servletRequest, pathParams);String extInPathParams = StringUtils.getFilenameExtension(pathParams);if (!safeExtension(servletRequest, ext) || !safeExtension(servletRequest, extInPathParams)) {headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline;filename=f.txt");}}
}

        safeExtension 方法在 extension 参数为空或 safeExtensions 属性中包含 extension 参数时直接返回 true,表明其安全;否则通过 RequestMappingInfoHandlerMapping 类的 handleMatch 方法设置的 BEST_MATCHING_PATTERN_ATTRIBUTE 属性设置的通过解析处理器方法获取到的最适配的路径判断是否当前扩展名是否与其匹配,匹配也是直接返回 true;随后单独判断扩展名是否 html 文件扩展名,再其为 html 文件且 PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE 属性中拥有 TEXT_HTML 值时也是返回 true;最后通过 resolveMediaType 方法解析扩展名对应媒体类型并通过 safeMediaType 判断其是否安全并返回。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {private boolean safeExtension(HttpServletRequest request, @Nullable String extension) {if (!StringUtils.hasText(extension)) {return true;}extension = extension.toLowerCase(Locale.ENGLISH);if (this.safeExtensions.contains(extension)) {return true;}String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);if (pattern != null && pattern.endsWith("." + extension)) {return true;}if (extension.equals("html")) {String name = HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(name);if (!CollectionUtils.isEmpty(mediaTypes) && mediaTypes.contains(MediaType.TEXT_HTML)) {return true;}}MediaType mediaType = resolveMediaType(request, extension);return (mediaType != null && (safeMediaType(mediaType)));}
}

        resolveMediaType 方法首先尝试从 Servlet 上下文中获取 extension 扩展名对应 MediaType,获取到非 APPLICATION_OCTET_STREAM 的媒体类型时直接返回;否则通过 MediaTypeFactory 获取对应媒体类型并返回。而 safeMediaType 方法则是通过使用拥有 +xml 结尾的自媒体类型或 SAFE_MEDIA_BASE_TYPES 常量判断媒体类型是否安全。

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {@Nullableprivate MediaType resolveMediaType(ServletRequest request, String extension) {MediaType result = null;String rawMimeType = request.getServletContext().getMimeType("file." + extension);if (StringUtils.hasText(rawMimeType)) {result = MediaType.parseMediaType(rawMimeType);}if (result == null || MediaType.APPLICATION_OCTET_STREAM.equals(result)) {result = MediaTypeFactory.getMediaType("file." + extension).orElse(null);}return result;}private boolean safeMediaType(MediaType mediaType) {return (SAFE_MEDIA_BASE_TYPES.contains(mediaType.getType()) ||mediaType.getSubtype().endsWith("+xml"));}
}

2.2 方法

2.2.1 supportsReturnType 方法

        supportsReturnType 方法直接判断方法或其外部类上是否使用 ResponseBody 注解进行修饰。

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

2.2.2 handleReturnValue 方法

        handleReturnValue 方法首先调用 mavContainer 的 setRequestHandled 将请求设置为已处理;随后依次调用 createInputMessage 与 createOutputMessage 创建 ServletServerHttpRequest 与 ServletServerHttpResponse 对象并调用 writeWithMessageConverters 方法使用消息转换器写入数据至响应之中。

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {@Overridepublic 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);}
}

3 异步响应处理器

        Spring 拥有三个异步响应结果处理器,分别为 AsyncTaskMethodReturnValueHandler、DeferredResultMethodReturnValueHandler 及 CallableMethodReturnValueHandler。他们的处理逻辑都是首先将结果转换为 WebAsyncManager 异步控制器可处理的类型,然后调用对应方法对转换后结果进行处理。

3.1 AsyncTaskMethodReturnValueHandler 

3.1.1 变量

        AsyncTaskMethodReturnValueHandler 类只有一个保存对象工厂的 beanFactory 变量。

public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnValueHandler {@Nullableprivate final BeanFactory beanFactory;public AsyncTaskMethodReturnValueHandler(@Nullable BeanFactory beanFactory) {this.beanFactory = beanFactory;}
}

3.1.2 supportsReturnType 方法

        supportsReturnType 方法直接返回返回值是否为 WebAsyncTask 对象。

public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnValueHandler {@Overridepublic boolean supportsReturnType(MethodParameter returnType) {return WebAsyncTask.class.isAssignableFrom(returnType.getParameterType());}
}

3.1.3 handleReturnValue 方法

        handleReturnValue 方法在 returnValue 为空时,直接将 mavContainer 参数设置为已处理并直接返回。随后将 WebAsyncTask 返回值的对象工厂设置为 beanFactory 变量值并调用 WebAsyncManager 异步控制器的 startCallableProcessing 方法开始处理异步结果。

public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnValueHandler {@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {if (returnValue == null) {mavContainer.setRequestHandled(true);return;}WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue;if (this.beanFactory != null) {webAsyncTask.setBeanFactory(this.beanFactory);}WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);}
}

3.2 CallableMethodReturnValueHandler

3.2.1 supportsReturnType 方法

        supportsReturnType 方法直接返回返回值是否为 Callable 对象。

public class CallableMethodReturnValueHandler implements HandlerMethodReturnValueHandler {@Overridepublic boolean supportsReturnType(MethodParameter returnType) {return Callable.class.isAssignableFrom(returnType.getParameterType());}
}

3.2.2 handleReturnValue 方法

        handleReturnValue 方法在 returnValue 为空时,直接将 mavContainer 参数设置为已处理并直接返回;否则直接调用 WebAsyncManager 异步控制器的 startCallableProcessing 方法开始处理异步结果。

public class CallableMethodReturnValueHandler implements HandlerMethodReturnValueHandler {@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {if (returnValue == null) {mavContainer.setRequestHandled(true);return;}Callable<?> callable = (Callable<?>) returnValue;WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);}
}

3.3 DeferredResultMethodReturnValueHandler

3.3.1 supportsReturnType 方法

        supportsReturnType 方法直接返回返回值是否为 DeferredResult、ListenableFuture 或 CompletionStage 对象。

public class DeferredResultMethodReturnValueHandler implements HandlerMethodReturnValueHandler {@Overridepublic boolean supportsReturnType(MethodParameter returnType) {Class<?> type = returnType.getParameterType();return (DeferredResult.class.isAssignableFrom(type) ||ListenableFuture.class.isAssignableFrom(type) ||CompletionStage.class.isAssignableFrom(type));}
}

 3.3.2 handleReturnValue 方法

        handleReturnValue 方法在 returnValue 为空时,也是直接将 mavContainer 参数设置为已处理并直接返回;否则直接调用对应的 adapt 适配器方法将返回参数转化为 DeferredResult 对象并调用 WebAsyncManager 异步控制器的 startDeferredResultProcessing 方法开始处理异步结果。

public class DeferredResultMethodReturnValueHandler implements HandlerMethodReturnValueHandler {@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {if (returnValue == null) {mavContainer.setRequestHandled(true);return;}DeferredResult<?> result;if (returnValue instanceof DeferredResult) {result = (DeferredResult<?>) returnValue;}else if (returnValue instanceof ListenableFuture) {result = adaptListenableFuture((ListenableFuture<?>) returnValue);}else if (returnValue instanceof CompletionStage) {result = adaptCompletionStage((CompletionStage<?>) returnValue);}else {// Should not happen...throw new IllegalStateException("Unexpected return value type: " + returnValue);}WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(result, mavContainer);}
}

        adaptListenableFuture 方法用于将 ListenableFuture 处理结果适配为 DeferredResult 对象,其通过向 ListenableFuture 类型参数中注入 ListenableFutureCallback 回调对象来实现 ListenableFuture 执行完成后对新建的 DeferredResult 对象赋值,其在执行成功时直接调用 result 的 setResult 方法设置返回值,执行失败时则回到用 setErrorResult 设置失败抛出的异常。

public class DeferredResultMethodReturnValueHandler implements HandlerMethodReturnValueHandler {private DeferredResult<Object> adaptListenableFuture(ListenableFuture<?> future) {DeferredResult<Object> result = new DeferredResult<>();future.addCallback(new ListenableFutureCallback<Object>() {@Overridepublic void onSuccess(@Nullable Object value) {result.setResult(value);}@Overridepublic void onFailure(Throwable ex) {result.setErrorResult(ex);}});return result;}
}

         adaptCompletionStage 方法用于将 CompletionStage 处理结果(我们常用的 CompletableFuture 等)适配为 DeferredResult 对象,其通过 handle 方法扩展进一步结果处理,其在处理完成后直接将执行异常或执行结果保存至新建的 DeferredResult 对象之中。

public class DeferredResultMethodReturnValueHandler implements HandlerMethodReturnValueHandler {private DeferredResult<Object> adaptListenableFuture(ListenableFuture<?> future) {DeferredResult<Object> result = new DeferredResult<>();future.addCallback(new ListenableFutureCallback<Object>() {@Overridepublic void onSuccess(@Nullable Object value) {result.setResult(value);}@Overridepublic void onFailure(Throwable ex) {result.setErrorResult(ex);}});return result;}
}

4 WebAsyncManager 类

4.1 变量

4.1.1 常量

        WebAsyncManager 类拥有 4 个常量,分别为标识空执行结果的 RESULT_NONE、保存默认异步任务执行器的 DEFAULT_TASK_EXECUTOR、Callable 结果处理超时拦截器 timeoutCallableInterceptor 及 DeferredResult 结果处理超时拦截器 timeoutDeferredResultInterceptor。

public final class WebAsyncManager {private static final Object RESULT_NONE = new Object();private static final AsyncTaskExecutor DEFAULT_TASK_EXECUTOR =new SimpleAsyncTaskExecutor(WebAsyncManager.class.getSimpleName());private static final CallableProcessingInterceptor timeoutCallableInterceptor =new TimeoutCallableProcessingInterceptor();private static final DeferredResultProcessingInterceptor timeoutDeferredResultInterceptor =new TimeoutDeferredResultProcessingInterceptor();
}

4.1.2 静态变量

        WebAsyncManager 类只有一个 taskExecutorWarning 静态变量,其用于标识是否已打印了未从 webAsyncTask 中获取到任务执行器的警告。

public final class WebAsyncManager {private static Boolean taskExecutorWarning = true;
}

4.1.3 类变量

        WebAsyncManager 类的类属性有封装当前请求响应的 asyncWebRequest 属性,异步任务执行器 taskExecutor,默认使用 DEFAULT_TASK_EXECUTOR 常量值,保存执行结果的 concurrentResult 属性,默认为 RESULT_NONE,concurrentResultContext 属性保存的则是当前异步结果上下文,errorHandlingInProgress 属性保存的是 concurrentResult 是否为异常,callableInterceptors 与 deferredResultInterceptors 属性分别保存为注册的  Callable 与 DeferredResult 结果处理拦截器映射。

public final class WebAsyncManager {private AsyncWebRequest asyncWebRequest;private AsyncTaskExecutor taskExecutor = DEFAULT_TASK_EXECUTOR;private volatile Object concurrentResult = RESULT_NONE;private volatile Object[] concurrentResultContext;private volatile boolean errorHandlingInProgress;private final Map<Object, CallableProcessingInterceptor> callableInterceptors = new LinkedHashMap<>();private final Map<Object, DeferredResultProcessingInterceptor> deferredResultInterceptors = new LinkedHashMap<>();
}

4.2 方法

4.2.1 startCallableProcessing 方法

        startCallableProcessing 方法首先将 asyncWebRequest 属性超时时间设置为 webAsyncTask 参数对应 timeout 超时时间值,之后则是 taskExecutor 执行器属性更新为 webAsyncTask 参数对应执行器,随后依次将 webAsyncTask 参数的拦截器、callableInterceptors 属性中的所有拦截器及 timeoutCallableInterceptor 超时拦截器添加到 interceptors 变量之中并使用该变量创建 CallableInterceptorChain 拦截器链并保存到 interceptorChain 变量中;之后依次设置超时处理器、异常处理器及执行处理器用于向其中添加拦截器,并在适当时调用 setConcurrentResultAndDispatch 方法设置结果并调度进响应。之后调用 interceptorChain 的 applyBeforeConcurrentHandling 方法进行前置处理,随后调用 startAsyncProcessing 方法开始异步处理,最后使用 taskExecutor 属性提交一个任务依次调用 interceptorChain 的 applyPreProcess 方法进行 callable 前置处理,调用 callable 的 call 方法获取执行结果及 interceptorChain 的 applyPostProcess 方法进行 callable 后置处理并在处理完成后调用 setConcurrentResultAndDispatch 方法设置异步结果并调度。  

public final class WebAsyncManager {public void startCallableProcessing(Callable<?> callable, Object... processingContext) throws Exception {Assert.notNull(callable, "Callable must not be null");startCallableProcessing(new WebAsyncTask(callable), processingContext);}public void startCallableProcessing(final WebAsyncTask<?> webAsyncTask, Object... processingContext)throws Exception {Assert.notNull(webAsyncTask, "WebAsyncTask must not be null");Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null");Long timeout = webAsyncTask.getTimeout();if (timeout != null) {this.asyncWebRequest.setTimeout(timeout);}AsyncTaskExecutor executor = webAsyncTask.getExecutor();if (executor != null) {this.taskExecutor = executor;}else {logExecutorWarning();}List<CallableProcessingInterceptor> interceptors = new ArrayList<>();interceptors.add(webAsyncTask.getInterceptor());interceptors.addAll(this.callableInterceptors.values());interceptors.add(timeoutCallableInterceptor);final Callable<?> callable = webAsyncTask.getCallable();final CallableInterceptorChain interceptorChain = new CallableInterceptorChain(interceptors);this.asyncWebRequest.addTimeoutHandler(() -> {if (logger.isDebugEnabled()) {logger.debug("Async request timeout for " + formatRequestUri());}Object result = interceptorChain.triggerAfterTimeout(this.asyncWebRequest, callable);if (result != CallableProcessingInterceptor.RESULT_NONE) {setConcurrentResultAndDispatch(result);}});this.asyncWebRequest.addErrorHandler(ex -> {if (!this.errorHandlingInProgress) {if (logger.isDebugEnabled()) {logger.debug("Async request error for " + formatRequestUri() + ": " + ex);}Object result = interceptorChain.triggerAfterError(this.asyncWebRequest, callable, ex);result = (result != CallableProcessingInterceptor.RESULT_NONE ? result : ex);setConcurrentResultAndDispatch(result);}});this.asyncWebRequest.addCompletionHandler(() ->interceptorChain.triggerAfterCompletion(this.asyncWebRequest, callable));interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, callable);startAsyncProcessing(processingContext);try {Future<?> future = this.taskExecutor.submit(() -> {Object result = null;try {interceptorChain.applyPreProcess(this.asyncWebRequest, callable);result = callable.call();}catch (Throwable ex) {result = ex;}finally {result = interceptorChain.applyPostProcess(this.asyncWebRequest, callable, result);}setConcurrentResultAndDispatch(result);});interceptorChain.setTaskFuture(future);}catch (RejectedExecutionException ex) {Object result = interceptorChain.applyPostProcess(this.asyncWebRequest, callable, ex);setConcurrentResultAndDispatch(result);throw ex;}}
}

4.2.2 startDeferredResultProcessing 方法

        startDeferredResultProcessing 方法首先将 asyncWebRequest 属性超时时间设置为 deferredResult 参数对应 timeout 超时时间值,随后依次将 deferredResult 参数的拦截器、deferredResultInterceptors 属性中的所有拦截器及 timeoutDeferredResultInterceptor 超时拦截器添加到 interceptors 变量之中并使用该变量创建 DeferredResultInterceptorChain 拦截器链并保存到 interceptorChain 变量之中;之后依次设置超时处理器、异常处理器及执行处理器用于在指定位置处执行拦截器,并在适当时调用 setConcurrentResultAndDispatch 方法设置结果并调度进响应。之后调用 interceptorChain 的 applyBeforeConcurrentHandling 方法进行前置处理,随后调用 startAsyncProcessing 方法开始异步处理;然后调用 interceptorChain 的 applyPreProcess 方法进行异步结果前置处理,最后将 deferredResult 的结果处理器设置为对结果执行 interceptorChain 的 applyPostProcess 方法进行结果后置处理并在最后调用 setConcurrentResultAndDispatch 方法设置结果并调度。

public final class WebAsyncManager {public void startDeferredResultProcessing(final DeferredResult<?> deferredResult, Object... processingContext) throws Exception {Assert.notNull(deferredResult, "DeferredResult must not be null");Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null");Long timeout = deferredResult.getTimeoutValue();if (timeout != null) {this.asyncWebRequest.setTimeout(timeout);}List<DeferredResultProcessingInterceptor> interceptors = new ArrayList<>();interceptors.add(deferredResult.getInterceptor());interceptors.addAll(this.deferredResultInterceptors.values());interceptors.add(timeoutDeferredResultInterceptor);final DeferredResultInterceptorChain interceptorChain = new DeferredResultInterceptorChain(interceptors);this.asyncWebRequest.addTimeoutHandler(() -> {try {interceptorChain.triggerAfterTimeout(this.asyncWebRequest, deferredResult);}catch (Throwable ex) {setConcurrentResultAndDispatch(ex);}});this.asyncWebRequest.addErrorHandler(ex -> {if (!this.errorHandlingInProgress) {try {if (!interceptorChain.triggerAfterError(this.asyncWebRequest, deferredResult, ex)) {return;}deferredResult.setErrorResult(ex);}catch (Throwable interceptorEx) {setConcurrentResultAndDispatch(interceptorEx);}}});this.asyncWebRequest.addCompletionHandler(()-> interceptorChain.triggerAfterCompletion(this.asyncWebRequest, deferredResult));interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, deferredResult);startAsyncProcessing(processingContext);try {interceptorChain.applyPreProcess(this.asyncWebRequest, deferredResult);deferredResult.setResultHandler(result -> {result = interceptorChain.applyPostProcess(this.asyncWebRequest, deferredResult, result);setConcurrentResultAndDispatch(result);});}catch (Throwable ex) {setConcurrentResultAndDispatch(ex);}}
}

4.2.3 startAsyncProcessing 方法

        startAsyncProcessing 方法首先依次将 concurrentResult、concurrentResultContext 及 errorHandlingInProgress 三个属性分别设置为 RESULT_NONE、 processingContext 参数及 false,最后调用 asyncWebRequest 属性的 startAsync 方法开始进行异步处理。

public final class WebAsyncManager {private void startAsyncProcessing(Object[] processingContext) {synchronized (WebAsyncManager.this) {this.concurrentResult = RESULT_NONE;this.concurrentResultContext = processingContext;this.errorHandlingInProgress = false;}this.asyncWebRequest.startAsync();if (logger.isDebugEnabled()) {logger.debug("Started async request");}}
}

4.2.4 setConcurrentResultAndDispatch 方法

        首先通过当前 concurrentResult 属性值判断是否已完成了响应结果的处理,在其值不为 RESULT_NONE 时表明结果已被处理,因此直接返回;否则将 concurrentResult 属性更新为 result 参数值并将 errorHandlingInProgress 参数更新为 result 参数是否为 Throwable 对象;并在 asyncWebRequest 属性的 isAsyncComplete 结果为 true时也是直接返回,最后调用 asyncWebRequest 属性的 dispatch 方法进行调度。

public final class WebAsyncManager {private void setConcurrentResultAndDispatch(Object result) {synchronized (WebAsyncManager.this) {if (this.concurrentResult != RESULT_NONE) {return;}this.concurrentResult = result;this.errorHandlingInProgress = (result instanceof Throwable);}if (this.asyncWebRequest.isAsyncComplete()) {if (logger.isDebugEnabled()) {logger.debug("Async result set but request already complete: " + formatRequestUri());}return;}if (logger.isDebugEnabled()) {boolean isError = result instanceof Throwable;logger.debug("Async " + (isError ? "error" : "result set") + ", dispatch to " + formatRequestUri());}this.asyncWebRequest.dispatch();}
}

5 ResponseBodyEmitterReturnValueHandler 类

5.1 变量

        ResponseBodyEmitterReturnValueHandler 类拥有三个属性,分别为原始消息转换器列表 messageConverters、SSE 协议使用的消息转换器列表 sseMessageConverters 及响应式结果处理器 reactiveHandler。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private final List<HttpMessageConverter<?>> messageConverters;private final List<HttpMessageConverter<?>> sseMessageConverters;private final ReactiveTypeHandler reactiveHandler;
}

5.2 方法

5.2.1 构造方法

        ResponseBodyEmitterReturnValueHandler 构造方法首先分别为 messageConverters 进行赋值,随后调用 initSseConverters 方法使用原始消息转换器列表初始化 sseMessageConverters,最后新建 ReactiveTypeHandler 对象用于初始化 reactiveHandler 属性。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {public ResponseBodyEmitterReturnValueHandler(List<HttpMessageConverter<?>> messageConverters) {Assert.notEmpty(messageConverters, "HttpMessageConverter List must not be empty");this.messageConverters = messageConverters;this.sseMessageConverters = initSseConverters(messageConverters);this.reactiveHandler = new ReactiveTypeHandler();}public ResponseBodyEmitterReturnValueHandler(List<HttpMessageConverter<?>> messageConverters,ReactiveAdapterRegistry registry, TaskExecutor executor, ContentNegotiationManager manager) {Assert.notEmpty(messageConverters, "HttpMessageConverter List must not be empty");this.messageConverters = messageConverters;this.sseMessageConverters = initSseConverters(messageConverters);this.reactiveHandler = new ReactiveTypeHandler(registry, executor, manager);}
}

        initSseConverters 方法主要用于增加处理字符串的消息转换器用于支持 SSE 协议;在 converters 参数中存在支持 TEXT_PLAIN 媒体类型的消息转换器时直接返回,否则向其中添加支持 UTF_8 字符的 StringHttpMessageConverter 消息转换器对象并返回。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private static List<HttpMessageConverter<?>> initSseConverters(List<HttpMessageConverter<?>> converters) {for (HttpMessageConverter<?> converter : converters) {if (converter.canWrite(String.class, MediaType.TEXT_PLAIN)) {return converters;}}List<HttpMessageConverter<?>> result = new ArrayList<>(converters.size() + 1);result.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));result.addAll(converters);return result;}
}

5.2.2 supportsReturnType 方法

        supportsReturnType 方法直接返回返回值是否为 ResponseBodyEmitter 对象或响应式对象。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {@Overridepublic boolean supportsReturnType(MethodParameter returnType) {Class<?> bodyType = ResponseEntity.class.isAssignableFrom(returnType.getParameterType()) ?ResolvableType.forMethodParameter(returnType).getGeneric().resolve() :returnType.getParameterType();return (bodyType != null && (ResponseBodyEmitter.class.isAssignableFrom(bodyType) ||this.reactiveHandler.isReactiveType(bodyType)));}
}

5.2.3 handleReturnValue 方法

        handleReturnValue 方法也会在 returnValue 返回值为空时直接设置为已处理并返回;随后将 webRequest 中包含的 Response 对象转化为 HttpServletResponse 对象并使用 ServletServerHttpResponse 对其进行封装并保存到 outputMessage 变量之中。在返回值为 ResponseEntity 对象时,首先会通过它设置对应的状态码与响应头,并更新 returnValue 与 returnType 变量值,并在实际返回值为空时直接返回。

        之后在 returnValue 变量不为 ResponseBodyEmitter 对象时,将会通过 reactiveHandler 属性的 handleValue 方法处理响应式结果并保存至 emitter 变量之中,在其为空时设置请求头之后直接返回,否则直接将返回值转换为 ResponseBodyEmitter 保存至 emitter 变量之中。之后依次通过 ResponseBodyEmitter 的 extendResponse 方法扩展响应(让 emitter 有机会自定义响应(设置 Content-Type 等)),ShallowEtagHeaderFilter 的 disableContentCaching 禁用缓存及使用 StreamingServletServerHttpResponse 对 outputMessage 进行封装并将封装值更新到 outputMessage 变量之中。

        最后使用 emitter 参数超时时间创建 DeferredResult 对象,并调用对应 WebAsyncManager 异步控制器的 startDeferredResultProcessing 方法启动对 DeferredResult 对象的处理最后使用 outputMessage 与 deferredResult 创建 HttpMessageConvertingHandler 对象,随后调用 emitter 的 initialize 方法对其进行初始化。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {@Override@SuppressWarnings("resource")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);Assert.state(response != null, "No HttpServletResponse");ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);if (returnValue instanceof ResponseEntity) {ResponseEntity<?> responseEntity = (ResponseEntity<?>) returnValue;response.setStatus(responseEntity.getStatusCodeValue());outputMessage.getHeaders().putAll(responseEntity.getHeaders());returnValue = responseEntity.getBody();returnType = returnType.nested();if (returnValue == null) {mavContainer.setRequestHandled(true);outputMessage.flush();return;}}ServletRequest request = webRequest.getNativeRequest(ServletRequest.class);Assert.state(request != null, "No ServletRequest");ResponseBodyEmitter emitter;if (returnValue instanceof ResponseBodyEmitter) {emitter = (ResponseBodyEmitter) returnValue;}else {emitter = this.reactiveHandler.handleValue(returnValue, returnType, mavContainer, webRequest);if (emitter == null) {// Not streaming: write headers without committing response..outputMessage.getHeaders().forEach((headerName, headerValues) -> {for (String headerValue : headerValues) {response.addHeader(headerName, headerValue);}});return;}}emitter.extendResponse(outputMessage);// At this point we know we're streaming..ShallowEtagHeaderFilter.disableContentCaching(request);// Wrap the response to ignore further header changes// Headers will be flushed at the first writeoutputMessage = new StreamingServletServerHttpResponse(outputMessage);HttpMessageConvertingHandler handler;try {DeferredResult<?> deferredResult = new DeferredResult<>(emitter.getTimeout());WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(deferredResult, mavContainer);handler = new HttpMessageConvertingHandler(outputMessage, deferredResult);}catch (Throwable ex) {emitter.initializeWithError(ex);throw ex;}emitter.initialize(handler);}
}

5.3 内部类

5.3.1 HttpMessageConvertingHandler 类

        HttpMessageConvertingHandler 类实现了 ResponseBodyEmitter.Handler 接口,用于监听处理 ResponseBodyEmitter 结果处理过程中的各类事件。

  • 属性

        HttpMessageConvertingHandler 类拥有两个属性,一个是保存响应对象的 outputMessage 属性,另一个则是用于保存异步处理结果的 deferredResult 属性。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private class HttpMessageConvertingHandler implements ResponseBodyEmitter.Handler {private final ServerHttpResponse outputMessage;private final DeferredResult<?> deferredResult;}
}
  • 构造方法

        HttpMessageConvertingHandler 类只有一个构造方法,直接为 outputMessage 与 deferredResult 两个属性赋值。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private class HttpMessageConvertingHandler implements ResponseBodyEmitter.Handler {public HttpMessageConvertingHandler(ServerHttpResponse outputMessage, DeferredResult<?> deferredResult) {this.outputMessage = outputMessage;this.deferredResult = deferredResult;}}
}
  • send 方法

        HttpMessageConvertingHandler 的 send 方法用于发送消息,其在接收到消息发送请求之后,其会选择与 mediaType 匹配的 HttpMessageConverter 消息转换器对象并调用其 write 方法发送数据,随后调用 outputMessage 的 flush 方法清空数据并返回。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private class HttpMessageConvertingHandler implements ResponseBodyEmitter.Handler {@Overridepublic void send(Object data, @Nullable MediaType mediaType) throws IOException {sendInternal(data, mediaType);}@SuppressWarnings("unchecked")private <T> void sendInternal(T data, @Nullable MediaType mediaType) throws IOException {for (HttpMessageConverter<?> converter : ResponseBodyEmitterReturnValueHandler.this.sseMessageConverters) {if (converter.canWrite(data.getClass(), mediaType)) {((HttpMessageConverter<T>) converter).write(data, mediaType, this.outputMessage);this.outputMessage.flush();return;}}throw new IllegalArgumentException("No suitable converter for " + data.getClass());}}
}
  • complete 方法

        complete 方法则用于请求完成后响应的刷新,其在刷新响应的同时会调用 deferredResult 的 setResult 方法将异步结果设置为 null。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private class HttpMessageConvertingHandler implements ResponseBodyEmitter.Handler {@Overridepublic void complete() {try {this.outputMessage.flush();this.deferredResult.setResult(null);}catch (IOException ex) {this.deferredResult.setErrorResult(ex);}}}
}
  • 其余方法

        其余方法则是直接调用 deferredResult 属性的对应方法进行响应处理。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private class HttpMessageConvertingHandler implements ResponseBodyEmitter.Handler {@Overridepublic void completeWithError(Throwable failure) {this.deferredResult.setErrorResult(failure);}@Overridepublic void onTimeout(Runnable callback) {this.deferredResult.onTimeout(callback);}@Overridepublic void onError(Consumer<Throwable> callback) {this.deferredResult.onError(callback);}@Overridepublic void onCompletion(Runnable callback) {this.deferredResult.onCompletion(callback);}}
}

5.3.2 StreamingServletServerHttpResponse

        StreamingServletServerHttpResponse 类实现了 ServerHttpResponse 接口专门用于处理流式响应中除第一次响应后不需发送响应头的问题。

  • 属性

        StreamingServletServerHttpResponse 类拥有两个属性,一个是保存原有响应对象的 delegate 属性,另一个则是用于保存响应头的 mutableHeaders 属性。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private static class StreamingServletServerHttpResponse implements ServerHttpResponse {private final ServerHttpResponse delegate;private final HttpHeaders mutableHeaders = new HttpHeaders();}
}
  • 构造方法

        StreamingServletServerHttpResponse 类的构造方法将原始 ServerHttpResponse 参数的响应头拆分出来放入到 mutableHeaders 属性中并将原始响应对象保存至 delegate 属性之中。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private static class StreamingServletServerHttpResponse implements ServerHttpResponse {public StreamingServletServerHttpResponse(ServerHttpResponse delegate) {this.delegate = delegate;this.mutableHeaders.putAll(delegate.getHeaders());}}
}
  • 其与方法

        StreamingServletServerHttpResponse 类除 getHeaders 之外的所有方法实现都是直接调用 delegate 的对应方法未做其他多余处理,而 getHeaders 方法则是返回 mutableHeaders 属性值。

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {private static class StreamingServletServerHttpResponse implements ServerHttpResponse {@Overridepublic void setStatusCode(HttpStatus status) {this.delegate.setStatusCode(status);}@Overridepublic HttpHeaders getHeaders() {return this.mutableHeaders;}@Overridepublic OutputStream getBody() throws IOException {return this.delegate.getBody();}@Overridepublic void flush() throws IOException {this.delegate.flush();}@Overridepublic void close() {this.delegate.close();}}
}

6 ResponseBodyEmitter 类

6.1 变量

        ResponseBodyEmitter 类拥有多个属性,其中 timeout 保存的是超时时间,handler 为使用的处理器,earlySendAttempts 与 failure 分别保存的是 handler 完成初始化完成之前已准备好等待发送的数据及异常、complete 属性保存的则是 handler 是否已完成了初始化、 sendFailed 属性则用于标识调用 handler 处理器的 send 方法发送消息时出现了异常、timeoutCallback、errorCallback 与 completionCallback 分别为超时、异常及完成回调对象。

public class ResponseBodyEmitter {@Nullableprivate final Long timeout;@Nullableprivate Handler handler;private final Set<DataWithMediaType> earlySendAttempts = new LinkedHashSet<>(8);private boolean complete;@Nullableprivate Throwable failure;private boolean sendFailed;private final DefaultCallback timeoutCallback = new DefaultCallback();private final ErrorCallback errorCallback = new ErrorCallback();private final DefaultCallback completionCallback = new DefaultCallback();public ResponseBodyEmitter(Long timeout) {this.timeout = timeout;}@Nullablepublic Long getTimeout() {return this.timeout;}
}

6.2 方法

6.2.1 初始化方法

  • initialize 方法

        initialize 方法正常的 handler 初始化,其将 handler 参数保存到 handler 属性中之后直接调用 sendInternal 方法将 earlySendAttempts 属性中的所有数据全部发送出去并在发送后清空 earlySendAttempts 属性。随后,若 complete 为 true,表明响应已结束,根据是否出现异常(failure 属性是否有值),调用 handler 属性的 completeWithError 方法处理带异常的关闭与 complete 方法正常关闭;否则依次调用 handler 的 onTimeout、onError 及 onCompletion 方法设置超时、异常及完成回调对象。

public class ResponseBodyEmitter {synchronized void initialize(Handler handler) throws IOException {this.handler = handler;try {for (DataWithMediaType sendAttempt : this.earlySendAttempts) {sendInternal(sendAttempt.getData(), sendAttempt.getMediaType());}}finally {this.earlySendAttempts.clear();}if (this.complete) {if (this.failure != null) {this.handler.completeWithError(this.failure);}else {this.handler.complete();}}else {this.handler.onTimeout(this.timeoutCallback);this.handler.onError(this.errorCallback);this.handler.onCompletion(this.completionCallback);}}
}
  • initializeWithError 方法

        initializeWithError 方法异常的 handler 初始化,其直接将 complete 属性置为 true,failure 更新为 ex 参数值、清空 earlySendAttempts 属性并利用 ex 参数执行 errorCallback 回调方法。

public class ResponseBodyEmitter {synchronized void initializeWithError(Throwable ex) {this.complete = true;this.failure = ex;this.earlySendAttempts.clear();this.errorCallback.accept(ex);}
}

6.2.2 extendResponse 方法

        extendResponse 方法旨在为自定义 ResponseBodyEmitter 类的子类提供一个可以更新响应状态码及响应头的方法。

public class ResponseBodyEmitter {protected void extendResponse(ServerHttpResponse outputMessage) {}
}

 6.2.3 send 方法

        send 方法直接调用 sendInternal 方法发送消息,其在 handler 不为空时直接调用其 send 方法发送消息,若出现异常则会将 sendFailed 属性置为 true 并抛出异常;否则只是使用 object 与 mediaType 创建 DataWithMediaType 对象并保存到 earlySendAttempts 属性之中。

public class ResponseBodyEmitter {public void send(Object object) throws IOException {send(object, null);}public synchronized void send(Object object, @Nullable MediaType mediaType) throws IOException {Assert.state(!this.complete,"ResponseBodyEmitter has already completed" +(this.failure != null ? " with error: " + this.failure : ""));sendInternal(object, mediaType);}private void sendInternal(Object object, @Nullable MediaType mediaType) throws IOException {if (this.handler != null) {try {this.handler.send(object, mediaType);}catch (IOException ex) {this.sendFailed = true;throw ex;}catch (Throwable ex) {this.sendFailed = true;throw new IllegalStateException("Failed to send " + object, ex);}}else {this.earlySendAttempts.add(new DataWithMediaType(object, mediaType));}}
}

6.2.4 complete 完成方法

        complete 与 completeWithError 方法分别为不带异常的结束与带异常的结束;他们首先都会验证 sendFailed 属性,若该属性为 true 直接返回,在其为 false 时都会将 complete 置为 true 并在 handler 不为空时调用其对应方法,唯一差异在于 completeWithError 方法会将 ex 参数值保存到 failure 属性之中。

public class ResponseBodyEmitter {public synchronized void complete() {// Ignore, after send failureif (this.sendFailed) {return;}this.complete = true;if (this.handler != null) {this.handler.complete();}}public synchronized void completeWithError(Throwable ex) {// Ignore, after send failureif (this.sendFailed) {return;}this.complete = true;this.failure = ex;if (this.handler != null) {this.handler.completeWithError(ex);}}
}

6.2.5 其他方法

        onTimeout、onError 及 onCompletion 三个方法都是用于向对应的回调对象中注入自定义回调逻辑。

public class ResponseBodyEmitter {public synchronized void onTimeout(Runnable callback) {this.timeoutCallback.setDelegate(callback);}public synchronized void onError(Consumer<Throwable> callback) {this.errorCallback.setDelegate(callback);}public synchronized void onCompletion(Runnable callback) {this.completionCallback.setDelegate(callback);}
}

6.3 内部类

6.3.1 Handler 接口

        Handler 接口的实现用于 ResponseBodyEmitter 对象动作的实际执行。

public class ResponseBodyEmitter {interface Handler {void send(Object data, @Nullable MediaType mediaType) throws IOException;void complete();void completeWithError(Throwable failure);void onTimeout(Runnable callback);void onError(Consumer<Throwable> callback);void onCompletion(Runnable callback);}
}

6.3.2 DataWithMediaType 类

        DataWithMediaType 类拥有两个属性,data 属性保存的是需要发送的数据,mediaType 属性保存的则是对应媒体类型。

public class ResponseBodyEmitter {public static class DataWithMediaType {private final Object data;@Nullableprivate final MediaType mediaType;public DataWithMediaType(Object data, @Nullable MediaType mediaType) {this.data = data;this.mediaType = mediaType;}public Object getData() {return this.data;}@Nullablepublic MediaType getMediaType() {return this.mediaType;}}
}

6.3.3 DefaultCallback 类

        DefaultCallback 类保存的默认回调对象,其拥有一个 delegate 属性,用于执行自定义回调逻辑,run 方法则会将 complete 属性置为 true 的同时执行 delegate 的 run 方法进行自定义回调处理。

public class ResponseBodyEmitter {private class DefaultCallback implements Runnable {@Nullableprivate Runnable delegate;public void setDelegate(Runnable delegate) {this.delegate = delegate;}@Overridepublic void run() {ResponseBodyEmitter.this.complete = true;if (this.delegate != null) {this.delegate.run();}}}
}

6.3.3 ErrorCallback 类

        ErrorCallback 类则是异常回调对象,其也拥有一个用于执行自定义回调逻辑的 delegate 属性,其 accept 方法也是在将 complete 属性置为 true 的同时执行 delegate 的 accept 方法进行自定义回调处理。

public class ResponseBodyEmitter {private class ErrorCallback implements Consumer<Throwable> {@Nullableprivate Consumer<Throwable> delegate;public void setDelegate(Consumer<Throwable> callback) {this.delegate = callback;}@Overridepublic void accept(Throwable t) {ResponseBodyEmitter.this.complete = true;if (this.delegate != null) {this.delegate.accept(t);}}}
}

http://www.dtcms.com/a/535751.html

相关文章:

  • everviz 数据可视化平台
  • 12 U盘挂载
  • 【Kylin Linux root 密码故障处置指南(超限重试 + 改回原密码)】
  • 网络原理:数据链路层、NAT与网页加载
  • 【从零开始开发远程桌面连接控制工具】01-项目概述与架构设计
  • 网站建设竞价托管什么意思在国内做推广产品用什么网站好
  • 有没有做宠物的网站网站开发中间商怎么做
  • 深度强化学习 | 详解从信赖域策略优化(TRPO)到近端策略优化(PPO)算法原理
  • 在类中定义装饰器:Python高级元编程技术详解
  • [C++][正则表达式]常用C++正则表达式用法
  • 基于大数据的短视频数据分析系统 Spark哔哩哔哩视频数据分析可视化系统 Hadoop大数据技术 情感分析 舆情分析 爬虫 推荐系统 协同过滤推荐算法 ✅
  • 参考抖音推荐算法的功能:不同用户规模的推荐技术框架
  • 深入理解C语言scanf函数:从基础到高级用法完全指南
  • 检测相邻递增子数组1 2(LeetCode 3349 3350)
  • 《算法闯关指南:优选算法--前缀和》--25.【模板】前缀和,26.【模板】二维前缀和
  • 快速搭建网站2020缅甸新闻最新消息
  • 搜索网站做推广全网推广平台推荐
  • 仓颉编程(16)泛型类型
  • 「小有可为」AI 开源公益创新挑战赛
  • 《 Linux 点滴漫谈: 四 》文件权限与用户管理
  • 评估虚拟机资源规划
  • 深入理解 SO_REUSEADDR:从“Address already in use”到服务器瞬间重启
  • 机器人中的多模态——RoboBrain
  • MySQL 8.0.x 全平台安装指南:Windows、CentOS、Ubuntu 详细步骤与问题解决
  • YOLO!!
  • 电子电气架构 --- 汽车座舱行业背景综述
  • C++(23):通过print和printIn进行输出
  • 获取网站访客qq号成都网站建设优点
  • 做一个同城便民信息网站怎么做公司给别人做的网站违法吗
  • 微算法科技(NASDAQ MLGO)探索自适应差分隐私机制(如AdaDP),根据任务复杂度动态调整噪声