Java SpringBoot

@RestController@Controller注解

都知道RestController默认都只提供Rest风格接口返回值,针对不需要返回页面的Controller都采用RestController进行注解,下面根据源码简单分析一下两者处理上的区别。
@RestController源码如下。

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Controller
  5. @ResponseBody
  6. public @interface RestController {
  7. /**
  8. * The value may indicate a suggestion for a logical component name,
  9. * to be turned into a Spring bean in case of an autodetected component.
  10. * @return the suggested component name, if any
  11. * @since 4.0.1
  12. */
  13. String value() default "";
  14. }

@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中完成。
RequestMappingHandlerAdapter#invokeHandlerMethod方法里面,有下面几句比较重要的代码

  1. //创建方法调用对象
  2. ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
  3. //......
  4. //设置返回值处理器
  5. invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
  6. //......
  7. //调用方法
  8. invocableMethod.invokeAndHandle(webRequest, mavContainer);

returnValueHandlers这个变量听名字就像返回值处理,实际上也是对返回值处理的处理器集合。首先创建一个调用方法的对象,然后注入处理器,最后调用方法,这就是完整的一个流程。
可以再分析一下这里面的处理器初始化时有没有针对@ResponseBody注解的处理器。

@ResponseBody注解处理器初始化

搜索一下returnValueHandlers初始化的地方,可以看到是这么个调用链:

  • RequestMappingHandlerAdapter#afterPropertiesSet

    • handlers = RequestMappingHandlerAdapter#getDefaultReturnValueHandlers

      1. returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers)

      所以是在RequestMappingHandlerAdapter的bean初始化完成时,就会进行返回值处理器的初始化,在RequestMappingHandlerAdapter#getDefaultReturnValueHandlers方法内部执行,代码如下。

      1. private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
      2. List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
      3. // Single-purpose return value types
      4. handlers.add(new ModelAndViewMethodReturnValueHandler());
      5. handlers.add(new ModelMethodProcessor());
      6. handlers.add(new ViewMethodReturnValueHandler());
      7. handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
      8. handlers.add(new StreamingResponseBodyReturnValueHandler());
      9. handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
      10. this.contentNegotiationManager, this.requestResponseBodyAdvice));
      11. handlers.add(new HttpHeadersReturnValueHandler());
      12. handlers.add(new CallableMethodReturnValueHandler());
      13. handlers.add(new DeferredResultMethodReturnValueHandler());
      14. handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
      15. // Annotation-based return value types
      16. handlers.add(new ModelAttributeMethodProcessor(false));
      17. //@ResponseBody注解处理器
      18. handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
      19. this.contentNegotiationManager, this.requestResponseBodyAdvice));
      20. // Multi-purpose return value types
      21. handlers.add(new ViewNameMethodReturnValueHandler());
      22. handlers.add(new MapMethodProcessor());
      23. // Custom return value types
      24. if (getCustomReturnValueHandlers() != null) {
      25. handlers.addAll(getCustomReturnValueHandlers());
      26. }
      27. // Catch-all
      28. if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
      29. handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
      30. }
      31. else {
      32. handlers.add(new ModelAttributeMethodProcessor(true));
      33. }
      34. return handlers;
      35. }

      可以看到非常对处理器,RequestResponseBodyMethodProcessor就是@ResponseBody的处理器。

      @ResponseBody注解处理器调用

      进入调用方法invocableMethod.invokeAndHandle(webRequest, mavContainer)/ServletInvocableHandlerMethod#invokeAndHandle,继续进行调用,跟踪调用链如下。

  • ServletInvocableHandlerMethod#invokeAndHandle

    • this.returnValueHandlers.handleReturnValue/HandlerMethodReturnValueHandlerComposite#handleReturnValue

HandlerMethodReturnValueHandlerComposite#handleReturnValue代码如下所示。

  1. public void handleReturnValue(Object returnValue, MethodParameter returnType,
  2. ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
  3. //选择一个合适的处理器
  4. HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
  5. if (handler == null) {
  6. throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
  7. }
  8. //处理返回值
  9. handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
  10. }

所以基本就是从所有处理器中选出目标处理器,处理返回值。进入HandlerMethodReturnValueHandlerComposite#selectHandler

  1. private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
  2. boolean isAsyncValue = isAsyncReturnValue(value, returnType);
  3. for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
  4. if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
  5. continue;
  6. }
  7. //判断处理器是否支持
  8. if (handler.supportsReturnType(returnType)) {
  9. return handler;
  10. }
  11. }
  12. return null;
  13. }

RequestResponseBodyMethodProcessor#supportsReturnType,代码如下。

  1. public boolean supportsReturnType(MethodParameter returnType) {
  2. return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
  3. returnType.hasMethodAnnotation(ResponseBody.class));
  4. }

明显如果类上有@ResponseBody或者方法上有的话,就能适配处理器,@RestController具有@ResponseBody语义能够适配,所以进行RequestResponseBodyMethodProcessor#handleReturnValue进行返回值处理。