1. HandlerMethodReturnValueHandler 概述
HandlerMethodReturnValueHandler = HandlerMethod(@RequestMapping的處理器) + returnValue(返回值) + Handler(處理器), 其實(shí)就是 HandlerMethod 返滬值的處理器, 將返回值以特定的格式輸出到client端, 或?qū)?View 相關(guān)的信息設(shè)置到 ModelAndViewContainer 里面, 以便于視圖的渲染, 其接口如下:
// HandlerMethod 的返回值處理器
public interface HandlerMethodReturnValueHandler {
// 判斷當(dāng)前處理器是否支持 返回值
boolean supportsReturnType(MethodParameter returnType);
// 處理 HandlerMethod 的返回值
void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
基于這個(gè)接口實(shí)現(xiàn)的處理器主要是如下幾類(lèi):
1. 返回值通常是View類(lèi)型或 ViewName 或 Map 類(lèi)型, 通常都是設(shè)置到 ModelAndViewContainer 里面
2. 支持返回值是 DeferredResult, ListenableFuture, CompletionStage 類(lèi)型, 最后轉(zhuǎn)為對(duì)應(yīng)的適配器, 交給WebAsyncManager 進(jìn)行運(yùn)行
3. 根據(jù) ContentType 的類(lèi)型將數(shù)據(jù)通過(guò) HttpMessageConverter 轉(zhuǎn)換成對(duì)應(yīng)的數(shù)據(jù)格式, 最后輸出到遠(yuǎn)端
2. 處理 View 或 String 類(lèi)型的HandlerMethodReturnValueHandler
1. ViewMethodReturnValueHandler
針對(duì) View 及其子類(lèi)的返回值處理器, 主要還是將 View 設(shè)置到 ModelAndViewContainer
2. ViewNameMethodReturnValueHandler
支持返回值為 CharSequence 類(lèi)型, 設(shè)置 ModelAndViewContainer.setViewName
3. StreamingResponseBodyReturnValueHandler
支持 StreamingResponseBody 類(lèi)型的返回值, 最后將請(qǐng)求包裝成 Callable, 通過(guò) Spring 的異步處理器 SimpleAsyncTaskExecutor 執(zhí)行 StreamingResponseBody 將數(shù)據(jù)流寫(xiě)到遠(yuǎn)端
4. ModelMethodProcessor
針對(duì) Model 及其子類(lèi)的返回值處理器, 主要還是將 ModelAndView 中的 model 設(shè)置到 ModelAndViewContainer
5. ModelAttributeMethodProcessor
針對(duì)被 @ModelAttribute 修飾的返回值, 最后將數(shù)據(jù)寫(xiě)入到 ModelAndViewContainer 中
6. ModelAndViewResolverMethodReturnValueHandler
通過(guò) ModelAndViewResolver 將數(shù)據(jù)解析成 View, Model, 最后設(shè)置到 ModelAndViewContainer 里面
7. ModelAndViewMethodReturnValueHandler
針對(duì) ModelAndView 及其子類(lèi)的返回值處理器, 主要還是將 ModelAndView 中的 status, model 設(shè)置到 ModelAndViewContainer
8. MapMethodProcessor
支持返回值為 Map, 并將結(jié)果設(shè)置到 ModelAndViewContainer
9. HttpHeadersReturnValueHandler
針對(duì) HttpHeaders 類(lèi)型的返回值, 最后設(shè)置到 Response 的 Header 中, 輸出到遠(yuǎn)端
上面幾個(gè) ReturnValueHandler 基本上就是將數(shù)據(jù)設(shè)置到 ModelAndViewContainer 里面
3. 處理異步返回值的 HandlerMethodReturnValueHandler
這一類(lèi)接口都是 AsyncHandlerMethodReturnValueHandler 的子類(lèi), 主要如下:
1. AsyncTaskMethodReturnValueHandler
支持返回值是 WebAsyncTask 類(lèi)型, 并通過(guò) WebAsyncManager 中的 SimpleAsyncTaskExecutor 來(lái)進(jìn)行處理
2. CallableMethodReturnValueHandler
支持返回值是 Callable 類(lèi)型, 并通過(guò) WebAsyncManager 中的 SimpleAsyncTaskExecutor 來(lái)進(jìn)行處理
3. CompletionStageReturnValueHandler
支持返回值是 CompletionStage 類(lèi)型, 并通過(guò) WebAsyncManager 中的 SimpleAsyncTaskExecutor 來(lái)進(jìn)行處理
4. DeferredResultMethodReturnValueHandler
這個(gè)類(lèi)適配 DeferredResult, ListenableFuture, CompletionStage 類(lèi)型的返回值, 最后通過(guò) WebAsyncManager 來(lái)完成任務(wù)的調(diào)用
5. ListenableFutureReturnValueHandler
支持返回值是 ListenableFuture 類(lèi)型, 并通過(guò) WebAsyncManager 中的 SimpleAsyncTaskExecutor 來(lái)進(jìn)行處理
4. 支持格式轉(zhuǎn)換的 HandlerMethodReturnValueHandler
這些 ReturnValueHandler 都是AbstractMessageConverterMethodProcessor的子類(lèi), 對(duì)應(yīng)實(shí)現(xiàn)的主邏輯也在 AbstractMessageConverterMethodProcessor 中
1. 獲取 request 對(duì)應(yīng)的 MediaType(PS: ContentNegotiationManager 進(jìn)行獲取 Request 所能支持的 MediaType)
2. 返回 HttpMessageConverter 所支持的 MediaType
3. 若 producibleMediaType 是空 且 返回值有數(shù)據(jù), 直接拋出異常
4. 找出 producibleMediaType 與 AcceptMediaType 都兼容的 MediaType
5. 循環(huán)遍歷 HttpMessageConverter, 進(jìn)行返回值的轉(zhuǎn)換處理 下面進(jìn)行選擇 converter 時(shí), 加入 MediaType 作為考慮
6. 通過(guò) ResponseBodyAdvice 在將數(shù)據(jù)寫(xiě)入輸出流之前進(jìn)行一些增強(qiáng)操作
7. 對(duì) Http 請(qǐng)求中的 header 進(jìn)行一些配置信息進(jìn)行處理
8. HttpMessageConverter 進(jìn)行處理, 將數(shù)據(jù)寫(xiě)入 outputStream, 并且寫(xiě)到遠(yuǎn)端
主流程的代碼如下:
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object outputValue; // 返回值內(nèi)容
Class<?> valueType; // 返回值類(lèi)型
Type declaredType;
if (value instanceof CharSequence) { // 若 value 是 Char
outputValue = value.toString(); // 設(shè)置 outputValue
valueType = String.class; // 設(shè)置 返回值的類(lèi)型
declaredType = String.class;
} else {
outputValue = value; // 設(shè)置返回值
valueType = getReturnValueType(outputValue, returnType); // 獲取 返回值的類(lèi)型
declaredType = getGenericType(returnType); // 返回值類(lèi)型
}
HttpServletRequest request = inputMessage.getServletRequest();
// 獲取 request 對(duì)應(yīng)的 MediaType(PS: ContentNegotiationManager 進(jìn)行獲取 Request 所能支持的 MediaType)
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
// 返回 HttpMessageConverter 所支持的 MediaType
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
// 若 producibleMediaType 是空 且 返回值有數(shù)據(jù), 直接拋出異常
if (outputValue != null && producibleMediaTypes.isEmpty()) throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
// 找出兩端都兼容的 MediaType
for (MediaType requestedType : requestedMediaTypes) {
// getMostSpecificMediaType 找出 兩個(gè) MediaType 中更加適合 producible
for (MediaType producibleType : producibleMediaTypes) if (requestedType.isCompatibleWith(producibleType)) compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
}
if (compatibleMediaTypes.isEmpty()) {
// 未出現(xiàn)兩者都兼容的 MediaType, 則直接拋出異常
if (outputValue != null) throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
return;
}
List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
// 將所有的 MediaType 進(jìn)行排序
MediaType.sortBySpecificityAndQuality(mediaTypes);
MediaType selectedMediaType = null;
// 篩選出其中一個(gè) mediaType
for (MediaType mediaType : mediaTypes) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
} else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; // 設(shè)置 application/octet-stream
break;
}
}
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
// 循環(huán)遍歷 HttpMessageConverter, 進(jìn)行返回值的轉(zhuǎn)換處理 下面進(jìn)行選擇 converter 時(shí), 加入 MediaType 作為考慮
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
// 下面分類(lèi) HttpMessageConverter 進(jìn)行分開(kāi)處理 <-- 先是支持 Type 的 HttpMessageConverter
if (messageConverter instanceof GenericHttpMessageConverter) {
if (((GenericHttpMessageConverter) messageConverter).canWrite(declaredType, valueType, selectedMediaType)) {
// 通過(guò) ResponseBodyAdvice 在將數(shù)據(jù)寫(xiě)入輸出流之前進(jìn)行一些增強(qiáng)操作
outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage);
if (outputValue != null) {
// 對(duì) Http 請(qǐng)求中的 header 進(jìn)行一些處理
addContentDispositionHeader(inputMessage, outputMessage);
// HttpMessageConverter 進(jìn)行處理, 將數(shù)據(jù)寫(xiě)入 outputStream, 并且寫(xiě)到遠(yuǎn)端
((GenericHttpMessageConverter) messageConverter).write(outputValue, declaredType, selectedMediaType, outputMessage);
logger.info("Written [" + outputValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]");
}
return;
}
}
// 普通 HttpMessageConverter 處理
else if (messageConverter.canWrite(valueType, selectedMediaType)) {
// 通過(guò) ResponseBodyAdvice 在將數(shù)據(jù)寫(xiě)入輸出流之前進(jìn)行一些增強(qiáng)操作
outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage);
if (outputValue != null) {
// 對(duì) Http 請(qǐng)求中的 header 進(jìn)行一些處理
addContentDispositionHeader(inputMessage, outputMessage);
// HttpMessageConverter 進(jìn)行處理, 將數(shù)據(jù)寫(xiě)入 outputStream, 并且寫(xiě)到遠(yuǎn)端
((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
logger.info("Written [" + outputValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]");
}
return;
}
}
}
if (outputValue != null) throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
而子類(lèi) HttpEntityMethodProcessor, RequestResponseBodyMethodProcessor, 先準(zhǔn)備數(shù)據(jù), 然后使用父類(lèi)的writeWithMessageConverters 方法, 將數(shù)據(jù)寫(xiě)入數(shù)據(jù)流中, 最后在刷到遠(yuǎn)端!
5. HandlerMethodReturnValueHandler 總結(jié)
總體上 HandlerMethodReturnValueHandler 的設(shè)計(jì)體系和HandlerMethodArgumentResolver 差不多, 設(shè)計(jì)上夾雜著策略, 模版, 適配器 等等, 而我們常用的 @ResponseBody 就是通過(guò)RequestResponseBodyMethodProcessor 來(lái)解決的(PS: 根據(jù) Http中的 acceptMedia 與 HttpMessageConverter 來(lái)進(jìn)行數(shù)據(jù)的轉(zhuǎn)換操作)!