当前位置: 首页 > 后端技术 > Java

深入分析RestController和Controller的区别,你真的看懂了吗?

时间:2023-04-01 19:03:59 Java

@RestController和@Controller注解我们都知道RestController默认只提供Rest风格的接口返回值,RestController用于注解不需要返回页面的Controller。下面根据源码简单分析一下两者在处理上的区别。@RestController源码如下。@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Controller@ResponseBodypublic@interfaceRestController{/***该值可能表示对逻辑组件名称的建议,*在Springcbean中转换一个自动检测的组件。*@return建议的组件名称,如果有*@since4.0.1*/Stringvalue()default"";}@RestController的写法取决于注解的组合,@RestController由@Controller和@ResponseBody标记,说明@RestController具有两者的注解语义,所以@RestController在注解处理过程中比@Controller多了一个@ResponseBody语义,这就是@RestController和@Controller的区别,也是为什么@RestController的返回值会被转换的原因json的原因。所以总结是:@RestController=@Controller+@ResponseBody;@ResponseBody注解的过程既然我们知道了@RestController和@Controller的区别在于多了一个@ResponseBody语义,那么我们不妨了解一下@ResponseBody的过程。首先可以知道@ResponseBody是一个注解,用于处理方法的返回值。如果熟悉SpringMVC的处理流程可以知道,根据requesturl映射得到HandlerMethod后,根据HandlerMethod调度请求方法的对象就是HandlerAdapter,方法调用结束,返回值处理的调度对象也是HandlerAdapter。所以@ResponseBody注解的处理也应该在HandlerAdapter中完成。在RequestMappingHandlerAdapter#invokeHandlerMethod方法中,有如下重要代码//创建方法调用对象ServletInvocableHandlerMethodinvocableMethod=createInvocableHandlerMethod(handlerMethod);//...//设置返回值处理器invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);//......//调用方法invocableMethod.invokeAndHandle(webRequest,mavContainer);变量returnValueHandlers听上去像是返回值处理,实际上是一个处理返回值的处理器集合。先创建对象调用方法,再注入处理器,最后调用方法,这是一个完整的过程。我们可以在processor初始化的时候再分析一下@ResponseBody注解是否有我们的processor。@ResponseBody注解处理器初始化搜索一下returnValueHandlers初始化的地方,可以看到是这么个调用链:RequestMappingHandlerAdapter#afterPropertiesSethandlers=RequestMappingHandlerAdapter#getDefaultReturnValueHandlersreturnValueHandlers?=?new?HandlerMethodReturnValueHandlerComposite().addHandlers(handlers)所以是在RequestMappingHandlerAdapter的bean初始化完成时,就ThereturnvaluehandlerwillbeinitializedandexecutedinsidetheRequestMappingHandlerAdapter#getDefaultReturnValueHandlersmethod,thecodeisasfollows.privateListgetDefaultReturnValueHandlers(){Listhandlers=newArrayList();//单一用途返回值类型handlers.add(newModelAndViewMethodReturnValueHandler());handlers.add(newModelMethodProcessor());handlers.add(newViewMethodReturnValueHandler());handlers.add(newResponseBodyEmitterReturnValueHandler(getMessageConverters()));handlers.add(newStreamingResponseBodyReturnValueHandler());handlers.add(newHttpEntityMethodProcessor(getMessageConverters(),this.contentNegotiationManager,this.requestResponseBodyAdvice));handlers.add(newHttpHeadersReturnValueHandler());handlers.add(newCallableMethodReturnValueHandler());handlers.add(newDeferredResultMethodReturnValueHandler());handlers.add(newAsyncTaskMethodReturnValueHandler(this.beanFactory));//基于注解的返回值etypeshandlers.add(newModelAttributeMethodProcessor(false));//@ResponseBody注册处理器handlers.add(newRequestResponseBodyMethodProcessor(getMessageConverters(),this.contentNegotiationManager,this.requestResponseBodyAdvice));//多用途返回值类型handlers.add(newViewNameMethodReturnValueHandler());handlers.add(newMapMethodProcessor());//自定义返回值类型if(getCustomReturnValueHandlers()!=null){handlers.addAll(getCustomReturnValueHandlers());}//Catch-allif(!CollectionUtils.isEmpty(getModelAndViewResolvers())){handlers.add(newModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));}else{handlers.add(newModelAttributeMethodProcessor(true));}returnhandlers;}可以看到非常对处理器,RequestResponseBodyMethodProcessor就是@ResponseBody的处理器@ResponseBody注解处理器调用进入调用方法invocableMethod.invokeAndHandle(webRequest,mavContainer)/ServletInvocableHandlerMethod#invokeAndHandle,继续调用,跟踪调用链如下。ServletInvocableHandlerMethod#invokeAndHandlethis.returnValueHandlers.handleReturnValue/HandlerMethodReturnValueHandlerComposite#handleReturnValueHandlerMethodReturnValueHandlerComposite#handleReturnValue代码如下所示。publicvoidhandleReturnValue(ObjectreturnValue,MethodParameterreturnType,ModelAndViewContainermavContainer,NativeWebRequestwebRequest)throwsException{//选择一个合适的处理器HandlerMethodReturnValueHandlerhandler=;selectHandler(returnValue,returnType)if(handler==null){thrownewIllegalArgumentException("未知返回值类型:"+returnType.getParameterType().getName());}//处理返回值handler.handleReturnValue(returnValue,returnType,mavContainer,webRequest);}所以,基本上是从所有处理器中选择目标Processor,处理返回值。进入HandlerMethodReturnValueHandlerComposite#selectHandlerprivateHandlerMethodReturnValueHandlerselectHandler(Objectvalue,MethodParameterreturnType){booleanisAsyncValue=isAsyncReturnValue(value,returnType);for(HandlerMethodReturnValueHandlerhandler:this.returnValueHandlers){if(isAsyncValue&&!(AsyncHandlerMethodReturnValueHandler的处理程序实例)){继续;}//判断处理器是否支持if(handler.supportsReturnType(returnType)){returnhandler;}}returnnull;}RequestResponseBodyMethodProcessor#supportsReturnType,代码如下。publicbooleansupportsReturnType(MethodParameterreturnType){return(AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(),ResponseBody.class)||returnType.hasMethodAnnotation(ResponseBody.class)Responsemethod;,处理器可以适配,@RestController有@ResponseBody语义并且可以适配,所以执行RequestResponseBodyMethodProcessor#handleReturnValue来处理返回值。