注解RestController与Controller的理解

1. 使用场景

@RestController: 针对不需要返回页面的Controller接口都采用RestController注解
@Controller: 在需要跳转页面的Controller接口使用Controller注解

2. 深入理解

@RestController的编写方式依赖注解组合,@RestController被@Controller和@ResponseBody标注,表示@RestController具有两者的注解语义,因此在注解处理时@RestController比@Controller多具有一个@ResponseBody语义,这就是@RestController和@Controller的区别,也是@RestController的返回值为何都是经过转换的json的原因。

所以小结就是:@RestController = @Controller + @ResponseBody;

@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 "";

}

@ResponseBody注解的处理过程

既然知道@RestController与@Controller的区别是多了一个@ResponseBody语义,我们不妨了解一下@ResponseBody的处理过程。

首先,可以知道,@ResponseBody是一个针对方法返回值进行处理的注解。如果熟悉Spring MVC处理过程的话,可以知道在根据requesturl映射获取到HandlerMethod之后,根据HandlerMethod调度请求方法的对象是HandlerAdapter,方法调用结束,返回值处理的调度对象也是HandlerAdapter。所以,@ResponseBody注解的处理应该也是在HandlerAdapter中完成。(ps:不清楚Spring MVC可以看深入分析Spring MVC)

在RequestMappingHandlerAdapter#invokeHandlerMethod方法里面,有下面几句比较重要的代码

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

@ResponseBody注解处理器初始化
搜索一下returnValueHandlers初始化的地方,可以看到是这么个调用链:

RequestMappingHandlerAdapter#afterPropertiesSet

handlers = RequestMappingHandlerAdapter#getDefaultReturnValueHandlers

returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers)

所以是在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;
}

可以看到非常对处理器,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);
}

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;
}

RequestResponseBodyMethodProcessor#supportsReturnType,代码如下。

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值