前言
Spring MVC处理入参靠的是HandlerMethodArgumentResolver这个接口,解析返回值靠的是HandlerMethodReturnValueHandler这个策略接口。
Spring MVC支持非常非常多的返回值类型,然后针对不同的返回值类型:比如Map、比如ViewName、比如Callable、比如异步的StreamingResponseBody等等都有其对应的处理器做处理,
一、返回值解析器架构
返回值解析器使用了策略模式+责任链模式
1、策略接口
HandlerMethodReturnValueHandler是返回值解析器的策略接口
public interface HandlerMethodReturnValueHandler {
// 每种处理器实现类,都对应着它能够处理的返回值类型~~~
boolean supportsReturnType(MethodParameter returnType);
// 简单的说就是处理返回值
void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
2、责任链包装类
同样的,他也使用了责任链模式进行调用,其责任链类是其子类HandlerMethodReturnValueHandlerComposite
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);
//。。。。
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
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;
}
//责任链类是是否存在,返回值解析器是AsyncHandlerMethodReturnValueHandler类型 ,且其isAsyncReturnValue返回true
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;
}
HandlerMethodReturnValueHandlerComposite中有个返回值解析器池。如果返回值解析器池中有AsyncHandlerMethodReturnValueHandler的子类,那就用他。如果没有判断其是否能解析返回值,如果能就返回他
public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodReturnValueHandler {
boolean isAsyncReturnValue(@Nullable Object returnValue, MethodParameter returnType);
}
注意:AsyncHandlerMethodReturnValueHandler跟异步处理返回值没有关系。目前版本是5.2, Spring中没有AsyncHandlerMethodReturnValueHandler的子类
接下来我们开始我们常用的返回值解析器
二、同步解析返回值解析器
1、@ResponseBody返回值解析器
它继承自AbstractMessageConverterMethodProcessor
。从名字或许就能看出来,这个处理器及其重要,因为它处理着我们最为重要的一个注解@ResponseBody
其实它还处理@RequestBody,只是我们这部分不讲请求参数, 并且它在读、写的时候和HttpMessageConverter还有深度结合
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
// 显然可以发现,方法上或者类上标注有@ResponseBody都是可以的~~~~
// 这也就是为什么现在@RestController可以代替我们的的@Controller + @ResponseBody生效了
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws ... {
// 首先就标记:此请求已经被处理了~~~
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// 这个方法是核心,也会处理null值~~~ 这里面一些Advice会生效~~~~
// 会选择到合适的HttpMessageConverter,然后进行消息转换(这里只指写~~~) 这个方法在父类上,是非常核心关键自然也是非常复杂的
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}
2、HttpEntity返回值解析器
显然它是处理返回值为HttpEntity类型的
public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor {
// 看这个判断。绝大多数情况下我们使用的返回值是ResponseEntity<T>
// 当然你也可以直接使用HttpEntity<T> 作为返回值也是可以的
public boolean supportsReturnType(MethodParameter returnType) {
return (HttpEntity.class.isAssignableFrom(returnType.getParameterType()) &&
!RequestEntity.class.isAssignableFrom(returnType.getParameterType()));
}
// 1、对请求中有Vary的进行特殊处理
// 2、Http状态码是200的话。如果是get请求或者Head请求,并且内容没有改变isResourceNotModified 那就直接outputMessage.flush() 然后return掉
// 3、做Http状态码是3打头(returnStatus / 100 == 3),如果有location的key,就特殊处理
// 最终,最终。正常情况下:依然同上调用父类writeWithMessageConverters()方法~~~
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
mavContainer.setRequestHandled(true);
if (returnValue == null) {
return;
}
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
//返回值类型判断
Assert.isInstanceOf(HttpEntity.class, returnValue);
HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue;
HttpHeaders outputHeaders = outputMessage.getHeaders();
HttpHeaders entityHeaders = responseEntity.getHeaders();
if (!entityHeaders.isEmpty()) {
entityHeaders.forEach((key, value) -> {
if (HttpHeaders.VARY.equals(key) && outputHeaders.containsKey(HttpHeaders.VARY)) {
List<String> values = getVaryRequestHeadersToAdd(outputHeaders, entityHeaders);
if (!values.isEmpty()) {
outputHeaders.setVary(values);
}
}
else {
outputHeaders.put(key, value);
}
});
}
if (responseEntity instanceof ResponseEntity) {
int returnStatus = ((ResponseEntity<?>) responseEntity).getStatusCodeValue();
outputMessage.getServletResponse().setStatus(returnStatus);
if (returnStatus == 200) {
if (SAFE_METHODS.contains(inputMessage.getMethod())
&& isResourceNotModified(inputMessage, outputMessage)) {
// 确保头已刷新,不应写入正文.
outputMessage.flush();
ShallowEtagHeaderFilter.disableContentCaching(inputMessage.getServletRequest());
// 跳过对转换器的调用,因为它们可能会更新主体.
return;
}
}
else if (returnStatus / 100 == 3) {
String location = outputHeaders.getFirst("location");
if (location != null) {
saveFlashAttributes(mavContainer, webRequest, location);
}
}
}
// 即使是空的身体也要试试。ResponseBodyAdvice可能会参与其.
writeWithMessageConverters(responseEntity.getBody(), returnType, inputMessage, outputMessage);
// 即使没有写入正文,也要确保刷新头.
outputMessage.flush();
}
显然,若我们想自己设置管理Http状态码,可以使用ResponseEntity。但显然绝大多数情况下,我们使用@ResponseBody更加的便捷~~~~
RequestResponseBodyMethodProcessor和HttpEntityMethodProcessor这2个类是当下最常用的返回值解析器,所以这里逃不开的要深入了解。毕竟它还和非常重要消息转换器也有非常重要的联系。所以要对父类方法writeWithMessageConverters()进行深入的解释:
AbstractMessageConverterMethodProcessor#writeWithMessageConverters详解
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
implements HandlerMethodReturnValueHandler {
...
protected <T> void writeWithMessageConverters( T value, MethodParameter returnType,ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)throws.... {
Object body;
Class<?> valueType;
Type targetType;
// 注意此处的特殊处理,相当于把所有的CharSequence类型的,都最终当作String类型处理的~
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());
}
// 若返回值是个org.springframework.core.io.Resource 就走这里 此处忽略~~
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());
}
}
}
// selectedMediaType表示最终被选中的MediaType,毕竟请求放可能是接受N多种MediaType的~~~
MediaType selectedMediaType = null;
// 一般情况下 请求方很少会指定contentType的~~~
// 如果请求方法指定了,就以它的为准,就相当于selectedMediaType 里面就被找打了
// 否则就靠系统自己去寻找到一个最为合适的~~~
MediaType contentType = outputMessage.getHeaders().getContentType();
if (contentType != null && contentType.isConcrete()) {
if (logger.isDebugEnabled()) {
logger.debug("Found 'Content-Type:" + contentType + "' in response");
}
selectedMediaType = contentType;
}
else {
HttpServletRequest request = inputMessage.getServletRequest();
// 获取浏览器可以接受的MediaType的集合
List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
// 这个方法就是从所有已经注册的转换器里面去找,看看哪些转换器.canWrite,然后把他们所支持的MediaType都加入进来~~~
// 比如此例只能匹配到MappingJackson2HttpMessageConverter,所以匹配上的有application/json、application/*+json两个
List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);
// 这个异常应该我们经常碰到:有body体,但是并没有能够支持的转换器,就是这额原因~~~
if (body != null && producibleTypes.isEmpty()) {
throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);
}
// 下面相当于从浏览器可议接受的MediaType里面,最终抉择出N个来
// 原理也非常简单:你能接受的isCompatibleWith上了我能处理的,那咱们就好说,处理就完了
List<MediaType> mediaTypesToUse = new ArrayList<>();
for (MediaType requestedType : acceptableTypes) {
for (MediaType producibleType : producibleTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
// 从两个中选择一个最匹配的 主要是根据q值来比较 排序
// 比如此例,最终匹配上的有两个:application/json;q=0.8和application/*+json;q=0.8
mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
// 这个异常也不少见,比如此处如果没有导入Jackson相关依赖包
// 就会抛出这个异常了:HttpMediaTypeNotAcceptableException:Could not find acceptable representation
if (mediaTypesToUse.isEmpty()) {
if (body != null) {
throw new HttpMediaTypeNotAcceptableException(producibleTypes);
}
if (logger.isDebugEnabled()) {
logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);
}
return;
}
// 根据Q值进行排序:
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;
}
}
}
// 最终的最终 都会找到一个决定write的类型,必粗此处为:application/json;q=0.8
// 因为最终会决策出来一个MediaType,所以此处就是要根据此MediaType找到一个合适的消息转换器,把body向outputstream写进去~~~
// 注意此处:是RequestResponseBodyAdviceChain执行之处~~~~
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> converter : this.messageConverters) {
// 从这个判断可以看出 ,处理body里面内容,GenericHttpMessageConverter类型的转换器是优先级更高,优先去处理的
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :converter.canWrite(valueType, selectedMediaType)) {
// 在写body之前执行~~~~ 会调用我们注册的所有的合适的ResponseBodyAdvice#beforeBodyWrite方法
// 相当于在写之前,我们可以介入对body体进行处理
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
if (body != null) {
Object theBody = body;
// 给响应Response设置一个Content-Disposition的请求头(若需要的话) 若之前已经设置过了,此处将什么都不做
// 比如我们常见的:response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "UTF-8"));
//Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。
// 当 Internet Explorer 接收到头时,它会激活文件下载对话框,它的文件名框自动填充了头中指定的文件名
addContentDispositionHeader(inputMessage, outputMessage);
if (genericConverter != null) {
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
// 如果return null,body里面是null 那就啥都不写,输出一个debug日志即可~~~~
else {
if (logger.isDebugEnabled()) {
logger.debug("Nothing to write: null body");
}
}
// 这一句表示:只要一个一个消息转换器处理了,就立马停止~~~~
return;
}
}
}
if (body != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
}
1、把所有的CharSequence类型的,都最终当作String类型处理
2、处理泛型
3、处理返回值是Resource
4、获取浏览器可以接受的MediaType的集合和查询可以解析当前返回值的消息解析器的所有MediaType的集合
5、匹配浏览器可以接受的MediaType的集合和我们可以解析的MediaType的集合,最终决定Response的MediaType
6、循环消息转换器,找出可以解析当前返回值的解析器。
7、调用我们注册的所有的合适的ResponseBodyAdvice,执行前置方法
8、调用消息转换器解析返回值
从上分析可以看出,这里面也提供了ResponseBodyAdvice钩子,我们可以通过实现此接口,来对接口的返回值进行干预、修改。相关注解为:@ControllerAdvice、@RestControllerAdvice
三、异步返回值解析器
1、StreamingResponseBody返回值解析器
处理情况说明:返回值直接是StreamingResponseBody类型,也支持你用ResponseEntity
在包一层,这里的包一层是指
ResponseEntity的泛型类型必须是StreamingResponseBody类型
public class StreamingResponseBodyReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
if (StreamingResponseBody.class.isAssignableFrom(returnType.getParameterType())) {
return true;
}
else if (ResponseEntity.class.isAssignableFrom(returnType.getParameterType())) {
Class<?> bodyType = ResolvableType.forMethodParameter(returnType).getGeneric().resolve();
return (bodyType != null && StreamingResponseBody.class.isAssignableFrom(bodyType));
}
return false;
}
@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();
if (returnValue == null) {
mavContainer.setRequestHandled(true);
outputMessage.flush();
return;
}
}
ServletRequest request = webRequest.getNativeRequest(ServletRequest.class);
Assert.state(request != null, "No ServletRequest");
ShallowEtagHeaderFilter.disableContentCaching(request);
Assert.isInstanceOf(StreamingResponseBody.class, returnValue, "StreamingResponseBody expected");
StreamingResponseBody streamingBody = (StreamingResponseBody) returnValue;
//最终也是开启了一个Callable 任务,最后交给WebAsyncUtils去执行的~~~~
Callable<Void> callable = new StreamingResponseBodyTask(outputMessage.getBody(), streamingBody);
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
}
private static class StreamingResponseBodyTask implements Callable<Void> {
private final OutputStream outputStream;
private final StreamingResponseBody streamingBody;
public StreamingResponseBodyTask(OutputStream outputStream, StreamingResponseBody streamingBody) {
this.outputStream = outputStream;
this.streamingBody = streamingBody;
}
@Override
public Void call() throws Exception {
this.streamingBody.writeTo(this.outputStream);
this.outputStream.flush();
return null;
}
}
}
2、DeferredResult返回值解析器
处理情况说明:返回值可以是DeferredResult,ListenableFuture或者CompletionStage类型
public class DeferredResultMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
Class<?> type = returnType.getParameterType();
return (DeferredResult.class.isAssignableFrom(type) ||
ListenableFuture.class.isAssignableFrom(type) ||
CompletionStage.class.isAssignableFrom(type));
}
@Override
public 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);
}
private DeferredResult<Object> adaptListenableFuture(ListenableFuture<?> future) {
DeferredResult<Object> result = new DeferredResult<>();
future.addCallback(new ListenableFutureCallback<Object>() {
@Override
public void onSuccess(@Nullable Object value) {
result.setResult(value);
}
@Override
public void onFailure(Throwable ex) {
result.setErrorResult(ex);
}
});
return result;
}
private DeferredResult<Object> adaptCompletionStage(CompletionStage<?> future) {
DeferredResult<Object> result = new DeferredResult<>();
future.handle((BiFunction<Object, Throwable, Object>) (value, ex) -> {
if (ex != null) {
if (ex instanceof CompletionException && ex.getCause() != null) {
ex = ex.getCause();
}
result.setErrorResult(ex);
}
else {
result.setResult(value);
}
return null;
});
return result;
}
}
3、Callable返回值解析器
处理情况说明:返回值必须是Callable类型
public class CallableMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return Callable.class.isAssignableFrom(returnType.getParameterType());
}
@Override
public 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);
}
}
4、WebAsyncTask返回值解析器
处理情况说明:返回值必须是WebAsyncTask类型
public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return WebAsyncTask.class.isAssignableFrom(returnType.getParameterType());
}
@Override
public 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);
}
}
5、ResponseBodyEmitter返回值解析器
处理情况说明:返回值必须是ResponseBodyEmitter类型,或也支持你用ResponseEntity
在包一层,这里的包一层是指
ResponseEntity的泛型类型必须是ResponseBodyEmitter类型
public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {
private final List<HttpMessageConverter<?>> messageConverters;
private final ReactiveTypeHandler reactiveHandler;
@Override
public 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)));
}
@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 write
outputMessage = new StreamingServletServerHttpResponse(outputMessage);
DeferredResult<?> deferredResult = new DeferredResult<>(emitter.getTimeout());
WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(deferredResult, mavContainer);
HttpMessageConvertingHandler handler = new HttpMessageConvertingHandler(outputMessage, deferredResult);
emitter.initialize(handler);
}
}