@Controller和@RestController源码解析

2018年不知不觉已经走到了尾声,你还在为分不清@Controller和@Restcontroller而烦恼吗?这篇博文从源码层面分析这两个注解,值得一读。

首先贴一张源码的图,对比一下,左边是@Controller的源码,右边是@RestController的。

如果觉得不清楚,看下面代码:

@Controller:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
     /**
      * 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 (or empty  String otherwise)
      */
     @AliasFor(annotation = Component.class)
     String value() default "";
}

@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 (or empty  String otherwise)
      * @since 4.0.1
      */
     @AliasFor(annotation = Controller.class)
     String value() default "";

}

显然,两个注解的源码里面都包含许多的注解:

@Controller的注解包括:@Target({ElementType.TYPE})、@Retention(RetentionPolicy.RUNTIME)、@Documented、@Component

@RestController的注解包括:@Target(ElementType.TYPE)、@Retention(RetentionPolicy.RUNTIME)、@Documented、@Controller、@ResponseBody

所以,源码的分析也就是对注解的分析。

内置注解和元注解

注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

Java SE5中有三种内置注解


@Override

表示当前的方法定义将覆盖超类中的方法

@Deprecated

如果程序中使用了注解为它的元素,那么编译器会发出警告

@SuppressWarnings

关闭不当的编译器警告信息

元注解是专门负责注解其他的注解,Java内置了四种元注解,专门负责新注解的创建,直接看这张表格(摘自Java编程思想):

@Target
表示该注解可以用于什么地方。可能的ElementType参数包括:

CONSTRUCTOR:构造器的声明

FIELD:域声明(包括enum实例)

LOCAL_VARIABLE:局部变量声明

METHOD:方法声明

PACKAGE:包声明

PARAMETER:参数声明

TYPE:类、接口(包括注解类型)和enum声明

@Retention
表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

SOURCE:注解将在编译器丢弃

CLASS:注解在class文件中可用,但会被VM丢弃

RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息

@Documented 将此注解包含在Javadoc中
@Inherited 允许子类继承父类中的注解

现在,明白了@Target({ElementType.TYPE})、@Retention(RetentionPolicy.RUNTIME)、@Documented的作用,我们也可以自定义一个注解@Algorithms:

/**
*
* Define a annotation named Algorithms
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Algorithms {
    String value() default "";
}

@Component注解

@Component注解源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {

     /**
      * 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 (or empty  String otherwise)
      */
     String value() default "";

}

加了@Component注解,表明这是一个逻辑组件,告知Spring要为它创建bean。相当于xml配置文件中的 <bean id="" class=""/>的作用。

@AliasFor注解

@AliasFor注解是一个用于声明注解属性别名的注解,源码如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AliasFor {

     /**
      * Alias for {@link #attribute}.
      * <p>Intended to be used instead of {@link #attribute}  when {@link #annotation}
      * is not declared &mdash; for example: {@code  @AliasFor("value")} instead of
      * {@code @AliasFor(attribute = "value")}.
      */
     @AliasFor("attribute")
     String value() default "";
     /**
      * The name of the attribute that <em>this</em> attribute  is an alias for.
      * @see #value
      */
     @AliasFor("value")
     String attribute() default "";
     /**
      * The type of annotation in which the aliased {@link  #attribute} is declared.
      * <p>Defaults to {@link Annotation}, implying that the  aliased attribute is
      * declared in the same annotation as <em>this</em>  attribute.
      */
     Class<? extends Annotation> annotation() default  Annotation.class;

}

@Controller中的@AliasFor(annotation = Component.class)说明@Controller是Component的一个别名,本质上还是一个Component,正如注释中所说“to be turned into a Spring bean in case of an  autodetected component.”,可以被扫描成一个bean。

同理,@RestController中的@AliasFor(annotation = Controller.class)说明@RestController是Controller的一个别名,是一个Controller,再本质一点说,是个Component,是个Spring bean。

@ResponseBody注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {

}

提到@ResponseBody注解,就不得不提一个名词:表述性状态转移(Representational State Transfer,REST)。

什么是表述性状态转移呢?拆开来看:

表述性:REST资源实际上可以用各种形式来表述,包括JSON、XML、HTML等;

状态:使用TEST的时候,我们更关注资源的状态而不是对资源采取的行为;

转移:以某种形式(例如JSON)从一个应用转换到另一个应用,例如从服务器到客户端。

简单讲,REST就是将资源的状态以最适合客户端或者服务器的形式从服务器转移到客户端(或者反过来)。

在Spring 4.0版本中,Spring支持借助@ResponseBody注解和各种HttpMethodConverter,替换基于视图的渲染方式,实现对REST的支持。当然Spring对REST的支持远不止这一种方式。

@ResponseBody注解告知Spring,要将返回的对象作为资源发送给客户端。这个过程跳过正常的模型/视图流程中视图解析的过程,而是使用Spring自带的各种Http消息转换器将控制器产生的数据转换为客户端需要的表述形式。如果客户端请求头的Accept表明他能接受“application/json”,并且Jackson JSON在类路径下面,那么处理方法返回的对象将交给MappingJacksonHTTPMessageConverter,并由他转换为JSON返回给客户端;如果客户端想要“text/html”格式,那么Jaxb2RootElementHttpMessageConverter将会为客户端产生XML响应。

当处理请求时候,@ResponseBody和@RequestBody是启用消息转换的一种简介和强大方式。但是,如果控制器里面的每个方法都需要信息转换功能的话,那么这些注解就会带有一定程度的重复性。

所以,Spring 4.0引入了@RestController注解,如果在控制器类上面使用@RestController注解,我们不必再为每个方法添加@ResponseBody注解,因为Spring会为该控制器下面的所有方法应用消息转换功能。这也是这个Controller之所以叫RestController的原因,正所谓见名知意。

总结

@RestController相当于@ResponseBody + @Controller一起作用。

如果控制器产生的结果希望让人看到,那么它产生的模型数据需要渲染到视图中,从而可以展示到浏览器中,使用@Controller。

如果控制器产生的结果不需要让人看到,那么它产生的数据经过消息转换器直接返回到浏览器,使用@RestController。

参考文献:

[1] Bruce Eckel. Java编程思想(第四版)[M]. 陈昊鹏译. 北京:机械工业出版社,2007.

[2] Craig Walls. Spring实战(第4版)[M]. 张卫滨译. 北京:人民邮电出版社,2016.

原文地址:https://www.cnblogs.com/sgh1023/p/10165470.html

时间: 2024-10-31 10:42:49

@Controller和@RestController源码解析的相关文章

rocketmq源码解析之NamesrvController创建

说在前面 本次开始进行rocketmq源码解析,比较喜欢rocketmq的架构设计,rocketmq内嵌了namesrv注册中心保存了元数据,进行负载均衡.容错的一些处理,4.3以上支持消息事务,有管理控制台.命令行工具,底层namesrv与broker.client与server交互netty实现. 源码解析 创建NamesrvController,进入这个方法org.apache.rocketmq.namesrv.NamesrvStartup#main,再进入这个方法org.apache.r

spring mvc源码解析

1.从DispatcherServlet开始     与很多使用广泛的MVC框架一样,SpringMVC使用的是FrontController模式,所有的设计都围绕DispatcherServlet 为中心来展开的.见下图,所有请求从DispatcherServlet进入,DispatcherServlet根据配置好的映射策略确定处理的 Controller,Controller处理完成返回ModelAndView,DispatcherServlet根据配置好的视图策略确定处理的 View,由V

Spring 源码解析之HandlerAdapter源码解析(二)

Spring 源码解析之HandlerAdapter源码解析(二) 前言 看这篇之前需要有Spring 源码解析之HandlerMapping源码解析(一)这篇的基础,这篇主要是把请求流程中的调用controller流程单独拿出来了 解决上篇文章遗留的问题 getHandler(processedRequest) 这个方法是如何查找到对应处理的HandlerExecutionChain和HandlerMapping的,比如说静态资源的处理和请求的处理肯定是不同的HandlerMapping ge

Fresco源码解析 - 初始化过程分析

使用Fresco之前,一定先要进行初始化,一般初始化的工作会在Application.onCreate()完成,当然也可以在使用Drawee之前完成. Fresco本身提供了两种初始化方式,一种是使用使用默认配置初始化,另一种是使用用户自定义配置. 如下代码是Fresco提供的两个初始化方法.第一个只需要提供一个Context参数,第二个还需要提供 ImagePipeline 的配置实例 - ImagePipelineConfig. /** Initializes Fresco with the

Spring 源码解析之ViewResolver源码解析(四)

Spring 源码解析之ViewResolver源码解析(四) 1 ViewResolver类功能解析 1.1 ViewResolver Interface to be implemented by objects that can resolve views by name. View state doesn't change during the running of the application, so implementations are free to cache views. I

MVC 路由源码解析

//到页面底部下载源,配合效果跟好. public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { RouteConfig.RegisterRoutes(RouteTable.Routes); //调用RouteConfig类的RegisterRoutes方法注册路由 //RouteTable.Routes是一个储存Route的集合 } } 我们转到RouteConf

spring MVC cors跨域实现源码解析 CorsConfiguration UrlBasedCorsConfigurationSource

spring MVC cors跨域实现源码解析 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就是跨域. spring MVC自4.2开始添加了跨域的支持. 跨域具体的定义请移步mozilla查看 使用案例 spring mvc中跨域使用有3种方式: 在web.xml中配置CorsFilter <filter> <filter-name>cors</filter-name> <

设计模式课程 设计模式精讲 12-3 适配器模式源码解析

1 源码解析 1.1 源码解析1(在jdk中的应用) 1.2 源码解析2(Spring中的通知管理) 1.3 源码解析3(SpringMVC中的应用) 1 源码解析 1.1 源码解析1(在jdk中的应用) xmlAdapter(此类是用于适配xml的一个类,是处理xml序列化和反序列化的一个类) public abstract class XmlAdapter<ValueType,BoundType> { /** * Do-nothing constructor for the derived

Spring Security 解析(七) —— Spring Security Oauth2 源码解析

Spring Security 解析(七) -- Spring Security Oauth2 源码解析 ??在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决定先把Spring Security .Spring Security Oauth2 等权限.认证相关的内容.原理及设计学习并整理一遍.本系列文章就是在学习的过程中加强印象和理解所撰写的,如有侵权请告知. 项目环境: JDK1.8 Spring boot 2.x Spring Security