日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

今天,我们来详细的聊一聊SpringBoot自动配置原理,学了这么久,你学废了吗?

發布時間:2025/3/19 javascript 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 今天,我们来详细的聊一聊SpringBoot自动配置原理,学了这么久,你学废了吗? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

SpringBoot是我們經常使用的框架,那么你能不能針對SpringBoot實現自動配置做一個詳細的介紹。如果可以的話,能不能畫一下實現自動配置的流程圖。牽扯到哪些關鍵類,以及哪些關鍵點。

下面我們一起來看看吧!!

前言:

閱讀完本文:

  • 你能知道 SpringBoot 啟動時的自動配置的原理知識
  • 你能知道 SpringBoot 啟動時的自動配置的流程
  • 以及對于 SpringBoot 一些常用注解的了解
  • 一步一步 debug 從淺到深。

    注意:本文的 SpringBoot 版本為 2.5.2

    一、啟動類

    前言什么的,就不說了,大家都會用的,我們直接從 SpringBoot 啟動類說起。

    @SpringBootApplication public class Hello {public static void main(String[] args) {SpringApplication.run(Hello.class);} }

    @SpringBootApplication 標注在某個類上說明這個類是 SpringBoot 的主配置類, SpringBoot 就應該運行這個類的main方法來啟動 SpringBoot 應用;是我們研究的重點!!!它的本質是一個組合注解,我們點進去,看看javadoc上是怎么寫的,分析從淺到深,從粗略到詳細。

    我們點進去看:

    @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {}

    Javadoc上是這么寫的

    表示聲明一個或多個@Bean方法并觸發 auto-configuration 和 component scanning 的 configuration 類。 這是一個方便的注解,相當于聲明了 @Configuration 、 @EnableAutoConfiguration 和@ComponentScan 。

    —為什么它能集成這么多的注解的功能呢?

    是在于它上面的 @Inherited 注解, @Inherited 表示自動繼承注解類型。

    這里的最重要的兩個注解是 @SpringBootConfiguration 和 @EnableAutoConfiguration。

    1.1、@SpringBootConfiguration

    我們先點進去看看 @SpringBootConfiguration注解:

    @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @Indexed public @interface SpringBootConfiguration {}

    1.2、@EnableAutoConfiguration

    再看看 @EnableAutoConfiguration.

    @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}

    1.3、@ComponentScan

    @ComponentScan:配置用于 Configuration 類的組件掃描指令。 提供與 Spring XML 的 <context:component-scan> 元素并行的支持。
    可以 basePackageClasses 或basePackages( 或其別名value )來定義要掃描的特定包。 如果沒有定義特定的包,將從聲明該注解的類的包開始掃描。

    作為了解,不是本文重點。

    1.4、探究方向

    主要探究圖中位于中間部分那條主線,其他只會稍做講解。

    二、@SpringBootConfiguration

    我們剛剛已經簡單看了一下 @SpringBootConfiguration 啦。

    @Configuration @Indexed public @interface SpringBootConfiguration {}

    它是 springboot 的配置類,標注在某個類上,表示這是一個 springboot的配置類。

    我們在這看到 @Configuration ,這個注解我們在 Spring 中就已經看到過了,它的意思就是將一個類標注為 Spring 的配置類,相當于之前 Spring 中的 xml 文件,可以向容器中注入組件。

    不是探究重點。

    三、@EnableAutoConfiguration

    我們來看看這玩意,它的字面意思就是:自動導入配置。

    @Inherited @AutoConfigurationPackage 自動導包 @Import(AutoConfigurationImportSelector.class) 自動配置導入選擇 public @interface EnableAutoConfiguration {}

    從這里顧名思義就能猜到這里肯定是跟自動配置有關系的。

    我們接著來看看這上面的兩個注解 @AutoConfigurationPackage 和 @Import(AutoConfigurationImportSelector.class) ,這兩個才是我們研究的重點。

    3.1、@AutoConfigurationPackage

    點進去一看:

    @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage {}

    @Import 為 spring 的注解,導入一個配置文件,在 springboot 中為給容器導入一個組件,而導入的組件由 AutoConfigurationPackages.Registrar.class 執行邏輯來決定的。

    往下👇看:Registrar

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));}@Overridepublic Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImports(metadata));} }

    在這個地方我們可以打個斷點,看看 new PackageImports(metadata).getPackageNames().toArray(new String[0]) 它是一個什么值。

    我們用 Evaluate 計算 new PackageImports(metadata).getPackageNames().toArray(new String[0]) 出來可以看到就是 com.crush.hello ,當前啟動類所在的包。

    繼續往下看的話就是和 Spring 注冊相關了,更深入 xdm 可以繼續 debug。

    在這里我們可以得到一個小小的結論

    @AutoConfigurationPackage 這個注解本身的含義就是將主配置類(@SpringBootApplication 標注的類)所在的包下面所有的組件都掃描到 spring 容器中。

    如果將一個 Controller 放到 com.crush.hello 以外就不會被掃描到了,就會報錯。

    3.2、@Import(AutoConfigurationImportSelector.class)

    AutoConfigurationImportSelector 開啟自動配置類的導包的選擇器(導入哪些組件的選擇器)

    我們點進 AutoConfigurationImportSelector 類來看看,有哪些重點知識,這個類中存在方法可以幫我們獲取所有的配置

    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {/**選擇需要導入的組件 ,*/@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}//根據導入的@Configuration類的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry 。protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);// 可以在這打個斷點,看看 返回的數據List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);//刪除重復項configurations = removeDuplicates(configurations);// 排除依賴Set<String> exclusions = getExclusions(annotationMetadata, attributes);//檢查checkExcludedClasses(configurations, exclusions);//刪除需要排除的依賴configurations.removeAll(exclusions);configurations = getConfigurationClassFilter().filter(configurations);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);} }

    我們看看這個斷點,configurations 數組長度為131,并且文件后綴名都為 **AutoConfiguration

    這里的意思是將所有需要導入的組件以全類名的方式返回,并添加到容器中,最終會給容器中導入非常多的自動配置類(xxxAutoConfiguration),給容器中導入這個場景需要的所有組件,并配置好這些組件。有了自動配置,就不需要我們自己手寫了。


    3.2.1、getCandidateConfigurations()

    我們還需要思考一下,這些配置都從 getCandidateConfigurations 方法中獲取,這個方法可以用來獲取所有候選的配置,那么這些候選的配置又是從哪來的呢?

    一步一步點進去:

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 這里有個 loadFactoryNames 方法 執行的時候還傳了兩個參數,一個是BeanClassLoader ,另一個是 getSpringFactoriesLoaderFactoryClass() 我們一起看看List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations; }

    看一下getSpringFactoriesLoaderFactoryClass()方法,這里傳過去的是

    protected Class<?> getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class; }

    這個 EnableAutoConfiguration 是不是特別眼熟,(我們探究的起點 @EnableAutoConfiguration ,有沒有感覺自己離答案越來越近啦)

    我們再看看 loadFactoryNames() 方法帶著它去做了什么處理:

    先是將 EnableAutoConfiguration.class 傳給了 factoryType ,然后 .getName( ) ,所以factoryTypeName 值為 EnableAutoConfiguration。

    3.2.2、loadSpringFactories()

    接下里又開始調用 loadSpringFactories 方法

    這里的 FACTORIES_RESOURCE_LOCATION 在上面有定義:

    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

    我們再回到 getCandidateConfigurations 方法處。

    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");

    這句斷言的意思是:“在 META-INF/spring.factories 中沒有找到自動配置類。如果您使用自定義包裝,請確保該文件是正確的。“

    這個 META-INF/spring.factories 在哪里呢?

    里面的內容:

    我們日常用到的,基本上都有一個配置類。

    比如 webmvc,

    我們點進 WebMvcProperties 類中去看一下:

    那這里到底是要干什么呢?

    這里的意思首先是把這個文件的 urls 拿到之后并把這些 urls 每一個遍歷,最終把這些文件整成一個properties 對象,loadProperties方法

    然后再從 properties 對象里邊獲取一些我們需要的值,把這些獲取到的值來加載我們最終要返回的這個結果,結果 result 為 map 集合,然后返回到loadFactoryNames方法中。

    然后我們再回到 loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); 的調用處。

    這個 factoryTypeName 值為 EnableAutoConfiguration

    因為 loadFactoryNames 方法攜帶過來的第一個參數為 EnableAutoConfiguration.class,所以 factoryType 值也為 EnableAutoConfiguration.class,那么 factoryTypeName 值為 EnableAutoConfiguration。

    那么map集合中 getOrDefault 方法為什么意思呢?意思就是當 Map 集合中有這個 key 時,就使用這個 key值,如果沒有就使用默認值 defaultValue (第二個參數),所以是判斷是否包含 EnableAutoConfiguration

    看下圖,這不就是嘛?

    所以就是把 spring-boot-autoconfigure-2.5.2.jar/META-INF/spring.factories 這個文件下的EnableAutoConfiguration 下面所有的組件,每一個 xxxAutoConfiguration 類都是容器中的一個組件,都加入到容器中。加入到容器中之后的作用就是用它們來做自動配置,這就是Springboot自動配置開始的地方。

    只有這些自動配置類進入到容器中以后,接下來這個自動配置類才開始進行啟動

    那 spring.factories 中存在那么多的配置,每次啟動時都是把它們全部加載嗎?

    是全部加載嘛?不可能的哈,這誰都知道哈,全部加載啟動一個項目不知道要多久去了。它是有選擇的。

    我們隨便點開一個類,都有這個 @ConditionalOnXXX 注解

    @Conditional 其實是 spring 底層注解,意思就是根據不同的條件,來進行自己不同的條件判斷,如果滿足指定的條件,那么整個配置類里邊的配置才會生效。

    所以在加載自動配置類的時候,并不是將 spring.factories 的配置全部加載進來,而是通過這個注解的判斷,如果注解中的類都存在,才會進行加載。

    這就是SpringBoot的自動配置啦.

    四、小結

    簡單總結起來就是:

    啟動類中有一個 @SpringBootApplication 注解,包含了 @SpringBootConfiguration、 @EnableAutoConfiguration , @EnableAutoConfiguration 代表開啟自動裝配,注解會去 spring-boot-autoconfigure 工程下尋找 META-INF/spring.factories 文件,此文件中列舉了所有能夠自動裝配類的清單,然后自動讀取里面的自動裝配配置類清單。因為有 @ConditionalOn 條件注解,滿足一定條件配置才會生效,否則不生效。 如: @ConditionalOnClass(某類.class) 工程中必須包含一些相關的類時,配置才會生效。所以說當我們的依賴中引入了一些對應的類之后,滿足了自動裝配的條件后,自動裝配才會被觸發。

    五、自言自語

    紙上得來終覺淺,絕知此事要躬行。

    如果可以,可以自己 debug 一遍,畫一畫流程圖。🛌 (躺平)

    你好,我是博主寧在春:主頁

    希望本篇文章能讓你感到有所收獲!!!

    祝 我們:待別日相見時,都已有所成。

    如有疑惑,大家可以留言評論。

    如有不足之處,請大家指出來,非常感謝 👨?💻。

    總結

    以上是生活随笔為你收集整理的今天,我们来详细的聊一聊SpringBoot自动配置原理,学了这么久,你学废了吗?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。