【Spring】抽丝剥茧SpringMVC-返回处理器HandlerMethodReturnValueHandler

本文深入解析了SpringMVC框架中HandlerMethodReturnValueHandler的实现类及其处理逻辑,包括ModelAndViewMethodReturnValueHandler、ModelMethodProcessor、ViewMethodReturnValueHandler、ResponseBodyEmitterReturnValueHandler、StreamingResponseBodyReturnValueHandler、HttpEntityMethodProcessor等,详细阐述了每个处理器支持的返回条件和处理过程,涉及模型绑定、视图解析、响应体处理等核心概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文源码基于SpringMVC 5.2.7

HandlerMethodReturnValueHandler

所有返回处理器都是HandlerMethodReturnValueHandler实现类。与参数处理器(HandlerMethodArgumentResolver)类似,HandlerMethodReturnValueHandler主要也有2个方法

boolean supportsReturnType(MethodParameter returnType)

  • 功能:支持的返回类型

void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)

  • 功能:处理返回值
  • 参数returnValue:返回值对象
  • 参数returnType:请求处理方法的返回类型
  • 参数mavContainer:ModelAndView的容器类对象,用来生成ModelAndView对象

SpringMVC框架提供了很多返回处理器,如下表所示

返回处理器支持的返回条件备注
ModelAndViewMethodReturnValueHandler

返回类型是ModelAndView及其子类

 
ModelMethodProcessor

返回类型是Model及其子类

 
ViewMethodReturnValueHandler

返回类型是View及其子类

 
ResponseBodyEmitterReturnValueHandler

以下条件任一

1. 返回类型是ResponseBodyEmitter及其子类

2. 返回类型是ResponseEntity及其子类且泛型类型是ResponseBodyEmitter及其子类

3. 返回类型属于响应式类型

 
StreamingResponseBodyReturnValueHandler

以下条件任一

1. 返回类型是StreamingResponseBody及其子类

2. 返回类型是ResponseEntity及其子类且ResponseEntity的泛型类型是StreamingResponseBody及其子类

 
HttpEntityMethodProcessor

返回类型是HttpEntity及其子类且不是RequestEntity及其子类

 
HttpHeadersReturnValueHandler

返回值类型是HttpHeaders及其子类

 
CallableMethodReturnValueHandler

以下条件任一

1. 返回值类型java.util.concurrent.Callable及其子类

2. 使用WebAsyncManager机制启动异步任务

 
DeferredResultMethodReturnValueHandler

以下条件任一

1. 返回值类型是DeferredResult及其子类

2. 返回值类型是ListenableFuture及其子类

3. 返回值类型是CompletionStage及其子类

 
AsyncTaskMethodReturnValueHandler

返回值类型是WebAsyncTask及其子类

 
ModelAttributeMethodProcessor

以下条件任一

1. 返回值类型有注解@ModelAttribute

2. ModelAttributeMethodProcessor的属性annotationNotRequired为true且返回值类型不是简单类型

 
RequestResponseBodyMethodProcessor

请求处理方法上有注解ResponseBody或者类上有注解@ResponseBody

 
ViewNameMethodReturnValueHandler

返回值类型是CharSequence及其子类或者void

 
MapMethodProcessor

返回值类型是java.util.Map及其子类

 
ModelAndViewResolverMethodReturnValueHandler

所有条件

 

ModelAndViewMethodReturnValueHandler

支持的返回条件

返回类型是ModelAndView及其子类

处理逻辑

1 如果returnValue的view是rediectView,则设置mavContainer属性redirectModelScenario为true表示使用重定向model

2 将returnValue的view赋值给mavContainer

3 将returnValue的model里元素添加到mavContainer中

 

ModelMethodProcessor

支持的返回条件

返回类型是Model及其子类

处理逻辑

将returnValue中的每个元素添加到mavContainer

ViewMethodReturnValueHandler

支持的返回条件

返回类型是View及其子类

处理逻辑

1. 如果returnValue是redirectView则设置mavContainer属性redirectModelScenario为true表示使用重定向model

2. 将returnValue赋值给mavContainer

ResponseBodyEmitterReturnValueHandler

支持的返回条件

以下三种条件任一

1. 返回类型是ResponseBodyEmitter及其子类

2. 返回类型是ResponseEntity及其子类且泛型类型是ResponseBodyEmitter及其子类

3. 返回类型属于响应式类型

处理逻辑

1 如果returnValue类型org.springframework.http.ResponseEntity,则

    1.1 将returnValue的状态设置到response中

    1.2 将ResponseEntity包含的实际对象赋值给returnValue

    1.3 returnValue为null 则flush response 结束流程并返回

2 如果是响应式类型(MOON、FLUX等)则转换为ResponseBodyEmitter对象(ReactiveTypeHandler)

3 创建DeferredResult对象

4 使用WebAsyncManager机制启动DeferredResult

5 创建ResponseBodyEmitterReturnValueHandler.HttpMessageConvertingHandler对象将returnValue(ResponseBodyEmitter)关联到DeferredResult对象。当ResponseBodyEmitter完成触发HttpMessageConvertingHandler完成,从而触发DeferredResult完成

public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {

... ...
    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) {
//笔者注:如果returnValue是ResponseEntity类型,且body是null,则设置请求已处理并flush response
				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<?> deferredResult = new DeferredResult<>(emitter.getTimeout());
        
        //笔者注:使用WebAsyncManager机制启动DeferredResult		WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(deferredResult, mavContainer);

        //笔者注:创建ResponseBodyEmitterReturnValueHandler.HttpMessageConvertingHandler对象将returnValue关联到DeferredResult对象。当returnValue完成触发HttpMessageConvertingHandler完成,从而触发DeferredResult完成
		HttpMessageConvertingHandler handler = new HttpMessageConvertingHandler(outputMessage, deferredResult);
		emitter.initialize(handler);
	}
    ... ...
}

StreamingResponseBodyReturnValueHandler

支持的返回条件

以下条件任一

1. 返回类型是StreamingResponseBody及其子类

2. 返回类型是ResponseEntity及其子类且ResponseEntity的泛型类型是StreamingResponseBody及其子类

处理逻辑

1. 创建任务StreamingResponseBodyTask

2. 使用WebAsyncManager机制启动任务异步将返回值写到 response并flush

public class StreamingResponseBodyReturnValueHandler implements HandlerMethodReturnValueHandler {
... ...
    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();
            
            //笔者注:如果返回的null,说明没有数据返回,直接flush空的并返回
			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;
        
        //笔者注:创建StreamingResponseBodyTask任务,并利用WebAsyncManager机制启动异步处理请求
		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

        //笔者注:StreamingResponseBodyTask任务将body写到response并flush
		public Void call() throws Exception {
			this.streamingBody.writeTo(this.outputStream);
			this.outputStream.flush();
			return null;
		}
	}
    ... ...
}

HttpEntityMethodProcessor

支持的返回条件

返回类型是HttpEntity及其子类且不是RequestEntity及其子类

处理逻辑

1 设置请求已处理

2 从returnValue中读取所有的headers设置到响应头

3 如果returnValue类型是org.springframework.http.ResponseEntity,则

    3.1 如果returnValue的状态是200且request method是GET或HEAD 且 资源unmodified 则直接flush并返回 否则进入3.2 (实战-unmodified)

    3.2 如果returnValue的状态是3xx且设置了"location"的响应头,则保存flashmap(flashmap用来在重定向场景将参数传递给target)

4 将returnValue的body写入到response并flush。参考AbstractMessageConverterMethodProcessor

AbstractMessageConverterMethodProcessor

AbstractMessageConverterMethodProcessor是AbstractMessageConverterMethodArgumentResolver子类,提供了将对象写入到response的功能AbstractMessageConverterMethodProcessor#writeWithMessageConverters

writeWithMessageConverters

1 确定value类型和目标类型以及body

2 如果返回值类型是Resource及其子类(不包括org.springframework.core.io.InputStreamResource),且 request包含请求头"Range" 则将返回值按请求头"Range"切割。修正value类型和目标类型以及body

3 确定响应头"Content-Type"

    3.1 如果响应头中已经设置具体的Content-Type直接用,否则进入3.2确认

    3.2 获取request中可接受的Media(AcceptableMediaTypes)服务可提供的Media(ProducibleMediaTypes)

    3.3 遍历 AcceptableMediaTypes 和 ProducibleMediaTypes,找到相匹配的MediaType集合

    3.4 排序MediaType集合,选择第一个具体的MediaType

4 如果确定了MediaType 则

    4.1 依次遍历messageConverters找到可以匹配的org.springframework.http.converter.HttpMessageConverter

    4.2 执行各匹配的ResponseBodyAdvice的写前处理(org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#beforeBodyWrite),并得到处理后的body

    4.3 将body写入到response

5 如果body不为null且没有在第4步写入response 则抛异常

public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
		implements HandlerMethodReturnValueHandler {
... ...
    //笔者注:将对象写入到response的功能
    protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
			ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		Object body;
		Class<?> valueType;
		Type targetType;

//笔者注:确定value的类型以及将要转换为的目标类型
		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());
		}

        //笔者注:如果是返回类型是资源类型,重新确认value和目标类型
		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
		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 {
            //笔者注:遍历 AcceptableMediaTypes 和 ProducibleMediaTypes,找到相匹配的MediaType集合
			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);
			}
		}

        //笔者注:确定了MediaType,遍历HttpMessageConverter将对象写到response
		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)) {

                    //笔者注:写入resonse前先执行before的逻辑
					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) {
                            
                            //笔者注:写入resonse
							genericConverter.write(body, targetType, selectedMediaType, outputMessage);
						}
						else {
                            //笔者注:写入resonse
							((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
						}
					}
					else {
						if (logger.isDebugEnabled()) {
							logger.debug("Nothing to write: null body");
						}
					}
					return;
				}
			}
		}

        //笔者注:如果body不为空且没有被写入response,则抛异常
		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);
		}
	}

... ...
}

HttpHeadersReturnValueHandler

支持的返回条件

返回值类型是HttpHeaders及其子类

处理逻辑

1. 设置请求已处理

2. 将returnValue中元素写入到response的headers

CallableMethodReturnValueHandler

支持的返回条件

以下条件任一

1. 返回值类型java.util.concurrent.Callable及其子类

2. 使用WebAsyncManager机制启动任务异步

DeferredResultMethodReturnValueHandler

支持的返回条件

以下条件任一

1. 返回值类型是DeferredResult及其子类

2. 返回值类型是ListenableFuture及其子类

3. 返回值类型是CompletionStage及其子类

处理逻辑

1 如果返回值类型是ListenableFuture及其子类或CompletionStage及其子类,则创建DeferredResult包装

2 使用WebAsyncManager机制启动DeferredResult,给DeferredResult添加结果处理器(DeferredResultHandler)

AsyncTaskMethodReturnValueHandler

支持的返回条件

返回值类型是WebAsyncTask及其子类

处理逻辑

使用WebAsyncManager机制启动WebAsyncTask

ModelAttributeMethodProcessor

支持的返回条件

以下条件任一

1. 返回值类型有注解@ModelAttribute

2. ModelAttributeMethodProcessor的属性annotationNotRequired为true且返回值类型不是简单类型,简单类型包括:基本类型及其包装类型、Date、Number、Enum、CharSequence、URL、URI、Temporal、Locale、Class等

处理逻辑

将返回值整体添加到mavContainer中,name取注解@ModelAttribute的属性value或者根据类型生成name

RequestResponseBodyMethodProcessor

支持的返回条件

请求处理方法上有注解ResponseBody或者类上有注解@ResponseBody

处理逻辑

1 设置request已处理

2 将returnValue写入到response。参考AbstractMessageConverterMethodProcessor

ViewNameMethodReturnValueHandler

支持的返回条件

返回值类型是CharSequence及其子类或者void

处理逻辑

1 如果返回值类型是CharSequence及其子类

    1.1 将returnValue设置给mavContainer的viewName

    1.2 如果returnValue是redirectview,则设置mavContainer的属性redirectModelScenario为true表示启动重定向model

2 如果返回值类型不是CharSequence及其子类且returnVaule不为null,则抛异常java.lang.UnsupportedOperationException

MapMethodProcessor

支持的返回条件

返回值类型是java.util.Map及其子类

处理逻辑

将returnValue中的所有元素添加到mavContainer中

ModelAndViewResolverMethodReturnValueHandler

支持的返回条件

所有条件

处理逻辑

1. 依次遍历mavResolvers,如果某个ModelAndViewResolver能够解析出ModelAndView对象,则将解析出的view设置给mavContainer的view,model中所有元素添加到mavContainer中

2. 如果1没有解析出,则使用modelAttributeProcessor处理返回值。如果modelAttributeProcessor也无法处理则抛出异常java.lang.UnsupportedOperationException

public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMethodReturnValueHandler {

... ...
    
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		if (this.mavResolvers != null) {

//笔者注:遍历所有的mavResolvers,是否能解出ModelAndView对象
			for (ModelAndViewResolver mavResolver : this.mavResolvers) {
				Class<?> handlerType = returnType.getContainingClass();
				Method method = returnType.getMethod();
				Assert.state(method != null, "No handler method");
				ExtendedModelMap model = (ExtendedModelMap) mavContainer.getModel();
				ModelAndView mav = mavResolver.resolveModelAndView(method, handlerType, returnValue, model, webRequest);
				if (mav != ModelAndViewResolver.UNRESOLVED) {
					mavContainer.addAllAttributes(mav.getModel());
					mavContainer.setViewName(mav.getViewName());
					if (!mav.isReference()) {
						mavContainer.setView(mav.getView());
					}
					return;
				}
			}
		}

		// No suitable ModelAndViewResolver...

        //笔者注:如果没有合适的ModelAndViewResolver能解出ModelAndView,则ModelAttributeProcessor处理器来处理,此处modelAttributeProcessor的属性annotationNotRequired是true,参考ModelAttributeProcessor处理逻辑。

		if (this.modelAttributeProcessor.supportsReturnType(returnType)) {
			this.modelAttributeProcessor.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
		}
		else {

            //笔者注:如果连modelAttributeProcessor都没有解出则抛异常
			throw new UnsupportedOperationException("Unexpected return type: " +
					returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
		}
	}

    ... ...
}


目录 目录

上一篇 ModelAttribute使用方法

下一篇 异步请求WebAsyncManager

再下一篇 异常解析器HandlerExceptionResolver

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值