springMVC返回值解析器HandlerMethodReturnValueHandler

前言

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);
	}
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值