當前位置:首頁 » 存儲配置 » 什麼是自動配置驅動

什麼是自動配置驅動

發布時間: 2025-08-23 05:33:23

1. SpringBoot核心原理:自動配置、事件驅動、Condition

SpringBoot是Spring的包裝,通過自動配置使得SpringBoot可以做到開箱即用,上手成本非常低,但是學習其實現原理的成本大大增加,需要先了解熟悉Spring原理。

如果還不清楚Spring原理的,可以先查看博主之前的文章,本篇主要分析SpringBoot的啟動、自動配置、Condition、事件驅動原理。

SpringBoot啟動非常簡單,因其內置了Tomcat,所以只需要通過下面幾種方式啟動即可:

可以看到第一種是最簡單的,也是最常用的方式,需要注意類上面需要標注 @SpringBootApplication 註解,這是自動配置的核心實現,稍後分析,先來看看SpringBoot啟動做了些什麼?

在往下之前,不妨先猜測一下,run方法中需要做什麼?對比Spring源碼,我們知道,Spring的啟動都會創建一個 ApplicationContext 的應用上下文對象,並調用其refresh方法啟動容器,SpringBoot只是Spring的一層殼,肯定也避免不了這樣的操作。

另一方面,以前通過Spring搭建的項目,都需要打成War包發布到Tomcat才行,而現在SpringBoot已經內置了Tomcat,只需要打成Jar包啟動即可,所以在run方法中肯定也會創建對應的Tomcat對象並啟動。以上只是我們的猜想,下面就來驗證,進入run方法:

SpringBoot的啟動流程就是這個方法,先看 getRunListeners 方法,這個方法就是去拿到所有的 SpringApplicationRunListener 實現類,這些類是用於SpringBoot事件發布的,關於事件驅動稍後分析,這里主要看這個方法的實現原理:

一步步追蹤下去可以看到最終就是通過SPI機制根據介面類型從 META-INF/spring.factories 文件中載入對應的實現類並實例化,SpringBoot的自動配置也是這樣實現的。

為什麼要這樣做呢?通過註解掃描不可以么?當然不行,這些類都在第三方jar包中,註解掃描實現是很麻煩的,當然你也可以通過 @Import 註解導入,但是這種方式不適合擴展類特別多的情況,所以這里採用SPI的優點就顯而易見了。

回到run方法中,可以看到調用了 createApplicationContext 方法,見名知意,這個就是去創建應用上下文對象:

注意這里通過反射實例化了一個新的沒見過的上下文對象 ,這個是SpringBoot擴展的,看看其構造方法:

如果你有看過Spring註解驅動的實現原理,這兩個對象肯定不會陌生,一個實支持註解解析的,另外一個是掃描包用的。

上下文創建好了,下一步自然就是調用refresh方法啟動容器:

這里首先會調用到其父類中 :

可以看到是直接委託給了父類:

這個方法不會陌生吧,之前已經分析過了,這里不再贅述,至此SpringBoot的容器就啟動了,但是Tomcat啟動是在哪裡呢?run方法中也沒有看到。

實際上Tomcat的啟動也是在refresh流程中,這個方法其中一步是調用了onRefresh方法,在Spring中這是一個沒有實現的模板方法,而SpringBoot就通過這個方法完成了Tomcat的啟動:

這里首先拿到 TomcatServletWebServerFactory 對象,通過該對象再去創建和啟動Tomcat:

上面的每一步都可以對比Tomcat的配置文件,需要注意默認只支持了http協議:

如果想要擴展的話則可以對 additionalTomcatConnectors 屬性設置值,需要注意這個屬性沒有對應的setter方法,只有 addAdditionalTomcatConnectors 方法,也就是說我們只能通過實現 BeanFactoryPostProcessor 介面的 postProcessBeanFactory 方法,而不能通過 的 方法,因為前者可以通過傳入的BeanFactory對象提前獲取到 TomcatServletWebServerFactory 對象調用 addAdditionalTomcatConnectors 即可;而後者只能拿到BeanDefinition對象,該對象只能通過setter方法設置值。

這段代碼會在控制台列印所有的事件名稱,按照順序如下:

以上是正常啟動關閉,如果發生異常還有發布 ApplicationFailedEvent 事件。事件的發布遍布在整個容器的啟動關閉周期中,事件發布對象剛剛我們也看到了是通過SPI載入的 SpringApplicationRunListener 實現類 EventPublishingRunListener ,同樣事件監聽器也是在 spring.factories 文件中配置的,默認實現了以下監聽器:

可以看到有用於文件編碼的( ),有載入日誌框架的( LoggingApplicationListener ),還有載入配置的( ConfigFileApplicationListener )等等一系列監聽器,SpringBoot也就是通過這系列監聽器將必要的配置和組件載入到容器中來,這里不再詳細分析,感興趣的讀者可以通過其實現的 onApplicationEvent 方法看到每個監聽器究竟是監聽的哪一個事件,當然事件發布和監聽我們自己也是可以擴展的。

SpringBoot最核心的還是自動配置,為什麼它能做到開箱即用,不再需要我們手動使用 @EnableXXX 等註解來開啟?這一切的答案就在 @SpringBootApplication 註解中:

這里重要的註解有三個: @SpringBootConfiguration 、 @EnableAutoConfiguration 、 @ComponentScan 。 @ComponentScan 就不用再說了, @SpringBootConfiguration 等同於 @Configuration ,而 @EnableAutoConfiguration 就是開啟自動配置:

@AutoConfigurationPackage 註解的作用就是將該註解所標記類所在的包作為自動配置的包,簡單看看就行,主要看 ,這個就是實現自動配置的核心類,注意這個類是實現的 DeferredImportSelector 介面。

在這個類中有一個 selectImports 方法。這個方法在我之前的文章這一次搞懂Spring事務註解的解析也有分析過,只是實現類不同,它同樣會被 類調用,先來看這個方法做了些什麼:

追蹤源碼最終可以看到也是從 META-INF/spring.factories 文件中拿到所有 EnableAutoConfiguration 對應的值(在 spring-boot-autoconfigure 中)並通過反射實例化,過濾後包裝成 AutoConfigurationEntry 對象返回。

看到這里你應該會覺得自動配置的實現就是通過這個 selectImports 方法,但實際上這個方法通常並不會被調用到,而是會調用該類的內部類 AutoConfigurationGroup 的process和selectImports方法,前者同樣是通過 getAutoConfigurationEntry 拿到所有的自動配置類,而後者這是過濾排序並包裝後返回。

下面就來分析 是怎麼調用到這里的,直接進入 processConfigBeanDefinitions 方法:

前面一大段主要是拿到合格的 Configuration 配置類,主要邏輯是在 ConfigurationClassParser.parse 方法中,該方法完成了對 @Component 、 @Bean 、 @Import 、 @ComponentScans 等註解的解析,這里主要看對 @Import 的解析,其它的讀者可自行分析。一步步追蹤,最終會進入到 processConfigurationClass 方法:

這里需要注意 this.conditionEvaluator.shouldSkip 方法的調用,這個方法就是進行Bean載入過濾的,即根據 @Condition 註解的匹配值判斷是否載入該Bean,具體實現稍後分析,繼續跟蹤主流程 doProcessConfigurationClass :

這里就是完成對一系列註解的支撐,我省略掉了,主要看 processImports 方法,這個方法就是處理 @Import 註解的:

剛剛我提醒過 是實現 DeferredImportSelector 介面的,如果不是該介面的實現類則是直接調用 selectImports 方法,反之則是調用 DeferredImportSelectorHandler.handle 方法:

首先創建了一個 DeferredImportSelectorHolder 對象,如果是第一次執行則是添加到 deferredImportSelectors 屬性中,等到 ConfigurationClassParser.parse 的最後調用process方法:

反之則是直接執行,首先通過register拿到 AutoConfigurationGroup 對象:

然後在 processGroupImports 方法中進行真正的處理:

在 getImports 方法中就完成了對process和 selectImports 方法的調用,拿到自動配置類後再遞歸調用調用 processImports 方法完成對自動配置類的載入。至此,自動配置的載入過程就分析完了,下面是時序圖:

在自動配置類中有很多Condition相關的註解,以AOP為例:

這里就能看到 @ConditionalOnProperty 、 @ConditionalOnClass 、 @ConditionalOnMissingClass ,另外還有 @ConditionalOnBean 、 @ConditionalOnMissingBean 等等很多條件匹配註解。

這些註解表示條件匹配才會載入該Bean,以 @ConditionalOnProperty 為例,表明配置文件中符合條件才會載入對應的Bean,prefix表示在配置文件中的前綴,name表示配置的名稱, havingValue 表示配置為該值時才匹配, matchIfMissing 則是表示沒有該配置是否默認載入對應的Bean。其它註解可類比理解記憶,下面主要來分析該註解的實現原理。

這里註解點進去看會發現每個註解上都標注了 @Conditional 註解,並且value值都對應一個類,比如 OnBeanCondition ,而這些類都實現了 Condition 介面,看看其繼承體系:

上面只展示了幾個實現類,但實際上Condition的實現類是非常多的,我們還可以自己實現該介面來擴展 @Condition 註解。Condition介面中有一個matches方法,這個方法返回true則表示匹配。該方法在 ConfigurationClassParser 中多處都有調用,也就是剛剛我提醒過的shouldSkip方法,具體實現是在 ConditionEvaluator 類中:

再來看看matches的實現,但 OnBeanCondition 類中沒有實現該方法,而是在其父類 SpringBootCondition 中:

getMatchOutcome 方法也是一個模板方法,具體的匹配邏輯就在這個方法中實現,該方法返回的 ConditionOutcome 對象就包含了是否匹配和日誌消息兩個欄位。進入到 OnBeanCondition 類中:

可以看到該類支持了 @ConditionalOnBean 、 @ConditionalOnSingleCandidate 、 @ConditionalOnMissingBean 註解,主要的匹配邏輯在 getMatchingBeans 方法中:

這里邏輯看起來比較復雜,但實際上就做了兩件事,首先通過 getNamesOfBeansIgnoredByType 方法調用 beanFactory.getBeanNamesForType 拿到容器中對應的Bean實例,然後根據返回的結果判斷哪些Bean存在,哪些Bean不存在(Condition註解中是可以配置多個值的)並返回MatchResult對象,而MatchResult中只要有一個Bean沒有匹配上就返回false,也就決定了當前Bean是否需要實例化。

本篇分析了SpringBoot核心原理的實現,通過本篇相信讀者也將能更加熟練地使用和擴展SpringBoot。

另外還有一些常用的組件我沒有展開分析,如事務、MVC、監聽器的自動配置,這些我們有了Spring源碼基礎的話下來看一下就明白了,這里就不贅述了。

最後讀者可以思考一下我們應該如何自定義starter啟動器,相信看完本篇應該難不倒你。

熱點內容
p30哪個配置銷量大 發布:2025-08-23 08:53:10 瀏覽:912
liunxsvn創建文件夾 發布:2025-08-23 08:23:11 瀏覽:738
日文解壓 發布:2025-08-23 08:02:24 瀏覽:629
街籃二蘋果怎麼和安卓玩游戲 發布:2025-08-23 07:56:47 瀏覽:64
linuxh3c 發布:2025-08-23 07:39:25 瀏覽:159
免費電腦主機伺服器 發布:2025-08-23 07:39:21 瀏覽:596
js是解釋執行還是編譯執行 發布:2025-08-23 07:24:23 瀏覽:529
vb循環腳本 發布:2025-08-23 07:18:31 瀏覽:745
拆了主機怎麼看配置 發布:2025-08-23 07:02:56 瀏覽:826
腳本做叔 發布:2025-08-23 07:00:23 瀏覽:243