SpringBoot2入門自動配置原理及源碼分析

SpringBoot自動配置

之前為什麼會去瞭解一些底層註解,其實就是為瞭後續更好的瞭解 springboot 底層的一些原理,比如自動配置原理。

一、@SpringBootApplication

從 MainApplication 中的@SpringBootApplication開始。

進入@SpringBootApplication,可以看到這是一個合成註解(紅框中是要關註的)。

1. @SpringBootConfiguration

這個註解幹嘛的?

直接點進去,發現有一個@Configuration註解,那這不就是個配置類嘛。

進而也說明瞭,MainApplication 也是一個配置類。

2. @ComponentScan

這個已經很熟悉瞭,可以指定掃描哪些 Spring 註解。

隻不過這裡,加瞭一些其他的過濾條件,暫時不關註。

3. @EnableAutoConfiguration

這個是最重要的註解瞭,聽名字就不一般,開啟自動配置。

點進去,發現也是一個合成註解(紅框需要關註)。

(1)@AutoConfigurationPackage

聽名字像是自動配置包?依舊點進去。

可以看到原來是導入瞭一個叫Registrar的組件,繼續點進 Registrar。

這裡是利用Registrar()給容器中導入一系列組件,也就是批量註冊組件。

在這裡打個斷點,debug 啟動一下。

registerBeanDefinitions()方法中有個傳參:

metadata,是註解的元信息,可以看到這個註解是被標註在com.pingguo.boot.MainApplication。

而在registerBeanDefinitions()方法體內,new 瞭一個AutoConfigurationPackages.PackageImports(),裡面傳入的是元註解,通過getPackageNames()獲取到包名。

AutoConfigurationPackages.register(
    registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0])
);

在 idea 中可以單獨執行下片段代碼

(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames()。

選中右擊,再點擊 Evaluate。

得到的結果就是com.pingguo.boot。為什麼是這個?因為註解標註在MainApplication類,而這個類就屬於com.pingguo.boot。

拿到包名之後,封裝到數組裡,也就是上述代碼片段中的toArray(new String[0]),最後註冊進去。

所以,這裡的Registrar()就是把指定的包下的所有組件批量註冊到容器中。

(2)@Import(AutoConfigurationImportSelector.class)

上面指定好默認包規則之後,就需要去導入需要的包瞭,利用的是AutoConfigurationImportSelector,繼續點進去看。

這裡有個selectImports方法,這個方法決定瞭要具體導入哪些,返回的是一個數組。

方法體內,又是調用瞭getAutoConfigurationEntry()方法來獲取配置入口,進而再通過getConfigurations()方法獲取具體配置,最終轉成數組返回。

顯然getAutoConfigurationEntry()是個重點。

往下翻一點,就是getAutoConfigurationEntry()的實現,在這裡打個斷點(把上面的斷點取消掉)。

debug重新運行一下,往下走到getCandidateConfigurations()。

這裡是獲取所有候選配置,目前可以看到這裡是共有 127 個。

為什麼是這 127 個?其實是在配置文件裡寫死瞭,在 springboot 啟動時候,給容器加載的所有場景的配置類。

定義的位置是在這:\spring-boot-autoconfigure\2.3.4.RELEASE\spring-boot-autoconfigure-2.3.4.RELEASE.jar!\META-INF\spring.factories

雖然這些一股腦的在啟動時候會去加載到容器,但是最終會按需開啟配置。

比如點開aop,看到@ConditionalOnClass({Advice.class})這個條件,是當存在Advice類時候才導入組件,但實際上這裡並沒有Advice。

這就是基於 springboot 的按條件裝配@Conditional,根據規則最終實現按需裝配。

二、自動配置示例

分別用最終未生效、和生效的自動配置來加深理解。

1. 未生效的自動配置

比如 cache。

可以看到CacheAutoConfiguration上是加瞭幾個條件裝配的。

(1)@ConditionalOnClass({CacheManager.class})

在 idea 中使用ctrl+N搜索一下CacheManager,發現是存在的,那麼這個條件滿足。

(2)@ConditionalOnBean({CacheAspectSupport.class})

這個條件是要求容器中存在CacheAspectSupport這個組件才可以。

現在來判斷一下是否存在這個組件,在 main 方法裡增加測試代碼:

... ...
      String[] beanNamesForType = run.getBeanNamesForType(CacheAspectSupport.class);
      System.out.println("==CacheAspectSupport類型組件的數量==" + beanNamesForType.length);
... ...

運行查看輸出。

發現數量等於 0,也就是不存在該類型的組件。

也就是說@ConditionalOnBean({CacheAspectSupport.class})這個條件不滿足,所以整個類CacheAutoConfiguration裡的配置都不生效。

2. 生效的自動配置

之前寫過 web 的demo,那麼 web 相關的配置自然是生效的,找到它。

這裡有不少後綴是**AutoConfiguration的配置,直接來看DispatcherServletAutoConfiguration。

  • @Configuration(proxyBeanMethods = false):表示是一個配置類。
  • @ConditionalOnWebApplication(type = Type.SERVLET):條件是否為一個 web 應用,而且是原生 SERVLET 類型的(因為springboot2還有webflux),當前滿足條件。
  • @ConditionalOnClass({DispatcherServlet.class}):條件是否導入瞭DispatcherServlet類,這裡也是有的。

還有 2 個註解直接沒見過,這裡不用太多關註,瞭解一下:

  • @AutoConfigureOrder:這個配置類的配置優先級順序。
  • @AutoConfigureAfter:表示在xx之後才配置這個類,這裡就是在配置完ServletWebServerFactoryAutoConfiguration.class後,再配置當前的類。

所以,類上的幾個條件都是滿足的,就可以進一步到類中瞭,繼續往下找:

看到DispatcherServletConfiguration類上也有條件:

@Conditional({DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition.class}):

別看這麼長,其實就是上面的一個類

@ConditionalOnClass({ServletRegistration.class}): 這個也存在。

@EnableConfigurationProperties({WebMvcProperties.class}):

這個很熟悉瞭,使用前面剛學習完不久,它並不是條件裝配,而是用來綁定外部配置文件的,點進去。

可以看到,會與配置文件中前綴是spring.mvc的所有屬性進行綁定。

另外,還可以自動把組件註冊到容器中去。

這裡可以試一下,在 main 方法裡增加輸出:

String[] beanNamesForType1 = run.getBeanNamesForType(WebMvcProperties.class);
    System.out.println("==WebMvcProperties類型組件的數量==" + beanNamesForType1.length);

運行一下,果然是有一個:

到此,說明DispatcherServletConfiguration這個配置類也是生效的。

繼續往下就看到方法dispatcherServlet(),而且是加瞭@Bean註解,就是給容器中註冊DispatcherServlet類型的組件。

這裡的經過是:

  • new 一個DispatcherServlet()對象dispatcherServlet
  • 接著對dispatcherServlet一通 set 設置。
  • 最後返回這個對象dispatcherServlet

在之前學習 springMVC 時候,還要手動去設置關於DispatcherServlet的一堆東西。而在 springboot 裡已經在底層設置好瞭,並且註冊到容器中去瞭,所以我們能直接使用。

三、小結

隨著進一步跟著源碼來理解自動配置的原理,使得自己更深的體會到 springboot 的優點。

那麼多東西不需要我們手動去配置瞭,並不是說用不上,而是在底層springboot已經幫我們完成好瞭配置。

當然,目前的重點還是學會使用 springboot,但是帶著之前對 springboot 的疑問來學習,還是更有收獲的。

以上就是SpringBoot2入門自動配置原理及源碼分析的詳細內容,更多關於SpringBoot2自動配置的資料請關註WalkonNet其它相關文章!

推薦閱讀: