面試官:好久沒見,甚是想念。今天來聊聊SpringBoot的自動配置吧?
候選者:嗯,SpringBoot的自動配置我覺得是SpringBoot很重要的“特性”了。眾所周知,SpringBoot有著“約定大於配置”的理念,這一理念一定程度上可以用“SpringBoot自動配置”來解釋。
候選者:SpringBoot自動配置的原理理解起來挺簡單的,我們在使用SpringBoot的時候,肯定會依賴於autoconfigure這麼一個包
候選者:autoconfigure這個包裡會有一個spring.factories檔案,該檔案定義了100+個入口的配置類。比如我們經常使用的redis、kafka等等這樣常見的中介軟體都預置了配置類
候選者:當我們在啟動SpringBoot專案的時候,內部就會載入這個spring.factories檔案,進而去載入“有需要”的配置類。那我們在使用相關元件的時候,就會非常的方便(因為配置類已經初始化了一大部分配置資訊)。
候選者:一般我們只要在application配置檔案寫上對應的配置,就能透過各種template類直接操作對應的元件啦。
面試官:那是所有的配置類都會載入嗎?這個“有需要”的配置類你是怎麼理解的?
候選者:不是所有的配置類都會載入的,假設我們沒有引入redis-starter的包,那Redis的配置類就不會被載入。具體Spring在實現的時候就是使用 @ConditionalXXX進行判斷的。比如Redis的配置類就會有@ConditionalOnClass({RedisOperations.class})的配置,說明當前環境下如果有RedisOperations.class這個位元組碼,才會去載入Redis的配置類
面試官:哦,這樣啊,那瞭解了。那你知不知道Redis的配置類其實會有初始化RedisTemplate物件的操作,那假設我們沒有引入redis-starter包,那他是怎麼透過編譯的?(當然了,其他的配置類也是有可能有一樣的狀況)
候選者:嗯,這個我看原始碼的時候我也發現了。其實就是在autoconfigure包裡會定義到相關的依賴,但只是標記為optional並且只在編譯環境有效。那這樣是能透過編譯的,只是不會將其依賴傳入到我們的應用工程裡。
候選者:這塊還是花了我很多時間的,我最後在GitHub 的SpringBoot原始碼裡找到的。
面試官:嗯啊,有點東西的喲。既然都聊到這塊了,要不順便聊聊你對SpringBoot starter的理解?
候選者:嗯,starter這東西就是為了方便呼叫方去使用相關的元件的嘛,Spring框架也給我們實現了很多好用的starter。
候選者:比如以前我們要用Mybatis框架,可能會引入各種的包才能使用。而starter就是做了一層封裝,把相關要用到的jar都給包起來了,並且也寫好了對應的版本。這我們使用的時候就不需要引入一堆jar包且管理版本類似的問題了。
候選者:現在很多開源的元件都會提供對應的springboot-starter包給我們去用,要做一個starter包並不難。參照Spring內建的實現就好了:1、在工程裡引入 starter 打包相關的依賴。2、在我們工程內建spring.factories檔案,編寫我們配置類的全限類名。
面試官:嗯,大致都瞭解了,可以的。最後聊下你是怎麼看這塊原始碼的?
候選者:原始碼具體大概就不記得了,思路倒是還有的。我先從啟動類開始,會有個@SpringBootApplication,後面會定位到一個自動配置的註解@EnableAutoConfiguration,那最後就能看到註解內部會去META-INF/spring.factories載入配置類
候選者:這塊原始碼並不難,這個過程也瞭解到了原來maven有option和scope這倆標籤,但確實是SpringBoot比較重要的概念吧。
面試官:好嘞,今天到這就結束了吧。
題外:自動配置這個問題確實被問到過幾次。說實在的,對於Spring類、註解的資訊我真的記不住。感覺能答出這個流程思路,也就夠用了(如果面試官確實是要細究某個類名,那這種公司不去也罷)
約定大於配置:SpringBoot給我們內建了很多配置類,這些配置類也初始化了很多配置(預設值)。當我們要使用的時候,只需要覆蓋這些配置項就完事了。即便我們不寫,大多數情況下都不需要由我們顯示配置出來,但相關元件就能正常訪問了。
推薦專案
如果想學Java專案的,我還是強烈推薦我的開源專案訊息推送平臺Austin,可以用作畢業設計,可以用作校招,可以看看生產環境是怎麼推送訊息的。
Gitee倉庫地址:https://gitee.com/zhongfucheng/austin
GitHub倉庫地址:https://github.com/ZhongFuCheng3y/austin