1230-深入分析RestController與Controller
深入分析RestController與Controller
2018年09月03日 12:31:41 不擼遊戲改擼程式碼 閱讀數:2249更多
https://blog.csdn.net/qq_20597727/article/details/82347014
@RestController和@Controller註解
我們都知道RestController預設都只提供Rest風格介面返回值,針對不需要返回頁面的Controller都採用RestController進行註解,下面根據原始碼簡單分析一下兩者處理上的區別。
@RestController原始碼如下。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @ResponseBody public @interface RestController { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any * @since 4.0.1 */ String value() default ""; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
@RestController的編寫方式依賴註解組合,@RestController被@Controller和@ResponseBody標註,表示@RestController具有兩者的註解語義,因此在註解處理時@RestController比@Controller多具有一個@ResponseBody語義,這就是@RestController和@Controller的區別,也是@RestController的返回值為何都是經過轉換的json的原因。
所以小結就是:@RestController = @Controller + @ResponseBody;
@ResponseBody註解的處理過程
既然知道@RestController與@Controller的區別是多了一個@ResponseBody語義,我們不妨瞭解一下@ResponseBody的處理過程。
首先,可以知道,@ResponseBody是一個針對方法返回值進行處理的註解。如果熟悉Spring MVC處理過程的話,可以知道在根據requesturl對映獲取到HandlerMethod之後,根據HandlerMethod排程請求方法的物件是HandlerAdapter,方法呼叫結束,返回值處理的排程物件也是HandlerAdapter。所以,@ResponseBody註解的處理應該也是在HandlerAdapter中完成。(ps:不清楚Spring MVC可以看
在RequestMappingHandlerAdapter#invokeHandlerMethod方法裡面,有下面幾句比較重要的程式碼
//建立方法呼叫物件
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//......
//設定返回值處理器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
//......
//呼叫方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
returnValueHandlers這個變數聽名字就像返回值處理,實際上也是對返回值處理的處理器集合。首先建立一個呼叫方法的物件,然後注入處理器,最後呼叫方法,這就是完整的一個流程。
我們可以再分析一下這裡面的處理器初始化時有沒有我們的針對@ResponseBody註解的處理器。
@ResponseBody註解處理器初始化
搜尋一下returnValueHandlers初始化的地方,可以看到是這麼個呼叫鏈:
-
RequestMappingHandlerAdapter#afterPropertiesSet
-
handlers = RequestMappingHandlerAdapter#getDefaultReturnValueHandlers
-
returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers)
- 1
-
所以是在RequestMappingHandlerAdapter的bean初始化完成時,就會進行返回值處理器的初始化,在RequestMappingHandlerAdapter#getDefaultReturnValueHandlers方法內部執行,程式碼如下。
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
//@ResponseBody註解處理器
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
可以看到非常對處理器,RequestResponseBodyMethodProcessor就是@ResponseBody的處理器。
@ResponseBody註解處理器呼叫
進入呼叫方法invocableMethod.invokeAndHandle(webRequest, mavContainer)/ServletInvocableHandlerMethod#invokeAndHandle,繼續進行呼叫,跟蹤呼叫鏈如下。
- ServletInvocableHandlerMethod#invokeAndHandle
- this.returnValueHandlers.handleReturnValue/HandlerMethodReturnValueHandlerComposite#handleReturnValue
HandlerMethodReturnValueHandlerComposite#handleReturnValue程式碼如下所示。
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//選擇一個合適的處理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
//處理返回值
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
so,基本就是從所有處理器中選出目標處理器,處理返回值。進入HandlerMethodReturnValueHandlerComposite#selectHandler
private HandlerMethodReturnValueHandler selectHandler(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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
RequestResponseBodyMethodProcessor#supportsReturnType,程式碼如下。
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
- 1
- 2
- 3
- 4
- 5
明顯如果類上有@ResponseBody或者方法上有的話,就能適配處理器,@RestController具有@ResponseBody語義能夠適配,所以進行RequestResponseBodyMethodProcessor#handleReturnValue進行返回值處理。