上一篇文章說了說Spring容器的作用,這次趁熱打鐵,看看Spring Boot中它是怎麼起作用的。

有了Spring容器之後,開發的模式簡化了很多,你的注意力基本只需要集中在編寫Bean上,比如@Controller類呀,@Service類呀,@Repository類呀等等。你新建了一個Spring Boot應用之後,隨便編寫一個控制器(Controller),他就可以用來處理網路請求了。按理說,一個控制器成為容器中的Bean,得有@ComponentScan來掃描呀,但是新建的應用也沒看到有配置類,更不用說依靠在其之上的@ComponentScan註解了。這一些都要從@SpringBootApplication說起。

上圖是很常見的Application類,用Spring Initializr生成的項目都有。它有個@SpringBootApplication註解,這個註解提供了Spring Boot的很多關鍵特性。我們打開SpringBootApplication的源碼看一看:

@SpringBootApplication是個組合註解(composed annotation),用它就相當於同時用了下面三個註解:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

Spring提供的很多註解都是元註解,組合註解就是由一個或者多個元註解組合成的。比方說@RestController,你寫純API服務的時候,控制器一般都用上它,它是由@Controller和@ResponseBody組合而成的,你直接把@RestController替換成這兩個,是可以的,他們是等效的。

如果你細心的話,會發現@Controller也是一個組合註解,元註解是@Component,所以說為什麼組件掃描能掃描到@Controller,原因就在這裡。

一個註解可能是元註解,也可能是組合註解,它倆只是個相對的概念。實際開發中,如果你的一個組件類加了好多註解,不妨自己去創建一個新的組合註解,這樣更清晰簡潔。更多相關內容,你可以看看Spring文檔裏關於元註解和組合註解的詳細說明。

廢了這麼多口舌,我就是想告訴你@SpringBootApplication目的就是為了方便地引入它的三個元註解

剛才我們說到了@ComponentScan,它用來告訴Spring容器去掃描組件,但是去哪裡掃描呢?它有一個String[]類型的註解參數basePackages,可以傳入需要掃描的路徑,如果你不傳,那就以當前類的包作為路徑。所以這麼一來,你的Application類在哪個包裏,自動掃描就在哪個包裏掃。你只要在這個包或者子包裏編寫@Controller類或者其他@Component類,都會被掃到的。假設你的Application類所在的包為com.fookwood.demo,那建議你所有的代碼都放這個包下,省得因為組件沒放入容器而出錯。

我們知道@ComponentScan都是跟著配置類一起出現的,但是沒見哪裡有@Configuration呀?因為有@SpringBootConfiguration了,他是個組合註解,把@Configuration帶來了。話說我找了很多資料,沒有發現@SpringBootConfiguration到底有什麼獨特作用,它的注釋上說一個程序通常只需要一個@SpringBootConfiguration就行了,而且大部分都是從@SpringBootApplication獲取的。那乾脆不管了,就當他是個@Configuration吧。

最後,該討論下@EnableAutoConfiguration了。他開啟了Spring Boot中最重要的特性—自動配置,自動配置可以根據你引入的依賴自動生成Bean等。大部分依賴都有對應一個叫做*AutoConfiguration的類,比如GSON有一個對應的GsonAutoConfiguration類:

看圖,他是一個正常的配置類,有@Configuration註解,但是呢,它的方法提供的Bean並不是直接加到容器裏的,而是需要滿足一定條件纔行。條件呢,通過@Conditional* 註解提供,GsonAutoConfiguration使用了@ConditionalOnClass註解,它的參數是Gson.class,意思就是,當類路徑中有Gson這個類的時候,GsonAutoConfiguration纔是一個真正的配置類。圖中的gsonBuilder方法新建了一個GsonBuilder對象,如果容器裏沒有這個類型的Bean,就使用新建的這個對象。圖中的gson方法,新建了一個Gson對象,如果容器裏沒有Gson類型的Bean,就把這個對象放進去。

所以說,一旦你在build.gradle中添加了GSON的依賴,那麼你就可以直接在自己的代碼裏引入Gson對象了,省事兒不?你要是想定義自己的Gson對象,當然可以,你可以在自己的配置類,添加你自己的GsonBuilder對象或者Gson對象,這樣的話,自動配置判斷容器裏已經有了,@Conditional*的條件不成立,就不自己搞了。

再提一句吧,雖然你的Application類(比如本文最上面的WhatEverApplication)也是一個配置類,你可以添加方法來創建新的Bean,不過我不喜歡這麼這麼做,我通常是新建單獨的配置類,比如新建一個名為WebConfig的類,在這個類裏定義Web開發相關的Bean。

博客鏈接:fookwood.com/spring-boo


推薦閱讀:
相關文章