本文源码基于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());
}
}
... ...
}
目录 目录