天天看點

@Controller和@RestController源碼解析

2018年不知不覺已經走到了尾聲,你還在為分不清@Controller和@Restcontroller而煩惱嗎?這篇博文從源碼層面分析這兩個注解,值得一讀。

首先貼一張源碼的圖,對比一下,左邊是@Controller的源碼,右邊是@RestController的。

@Controller和@RestController源碼解析

如果覺得不清楚,看下面代碼:

@Controller:

@Controller和@RestController源碼解析
@Controller和@RestController源碼解析

View Code

@RestController:

@Controller和@RestController源碼解析
@Controller和@RestController源碼解析

顯然,兩個注解的源碼裡面都包含許多的注解:

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

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

是以,源碼的分析也就是對注解的分析。

注解(也被稱為中繼資料)為我們在代碼中添加資訊提供了一種形式化的方法,使我們可以在稍後某個時刻非常友善地使用這些資料。

Java SE5中有三種内置注解:

<col>

@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:

@Component注解源碼如下:

加了@Component注解,表明這是一個邏輯元件,告知Spring要為它建立bean。相當于xml配置檔案中的 &lt;bean id="" class=""/&gt;的作用。

@AliasFor注解是一個用于聲明注解屬性别名的注解,源碼如下:

@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注解,就不得不提一個名詞:表述性狀态轉移(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.

由于部落客也是在攀登的路上,文中可能存在不當之處,歡迎各位多指教! 如果文章對您有用,那麼請點個”推薦“,以資鼓勵!

繼續閱讀