欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot自動配置原理分析

 更新時間:2022年08月16日 08:57:39   作者:寧在春  
這篇文章主要介紹了SpringBoot自動配置原理分析,SpringBoot是我們經(jīng)常使用的框架,那么你能不能針對SpringBoot實現(xiàn)自動配置做一個詳細(xì)的介紹。如果可以的話,能不能畫一下實現(xiàn)自動配置的流程圖。牽扯到哪些關(guān)鍵類,以及哪些關(guān)鍵點

前言

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

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

閱讀完本文:

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

一步一步 debug 從淺到深。

注意本文的 SpringBoot 版本為 2.5.2

一、啟動類

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

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

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

我們點進去看:

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

Javadoc上是這么寫的

表示聲明一個或多個@Bean方法并觸發(fā) auto-configuration 和 component scanning 的 configuration 類。 這是一個方便的注解,相當(dāng)于聲明了 @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

我們剛剛已經(jīng)簡單看了一下 @SpringBootConfiguration 啦。

@Configuration
@Indexed
public @interface SpringBootConfiguration {}

它是 springboot 的配置類,標(biāo)注在某個類上,表示這是一個 springboot的配置類。

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

不是探究重點。

三、@EnableAutoConfiguration

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

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

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

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

3.1、@AutoConfigurationPackage

點進去一看:

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

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

往下??看:Registrar

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
    }

    @Override
    public 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 ,當(dāng)前啟動類所在的包。

繼續(xù)往下看的話就是和 Spring 注冊相關(guān)了,更深入 xdm 可以繼續(xù) debug。

在這里我們可以得到一個小小的結(jié)論

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

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

3.2、@Import(AutoConfigurationImportSelector.class)

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

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

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

    /**選擇需要導(dǎo)入的組件 ,*/
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}
    //根據(jù)導(dǎo)入的@Configuration類的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry 。
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 可以在這打個斷點,看看 返回的數(shù)據(jù)
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        //刪除重復(fù)項
		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 數(shù)組長度為131,并且文件后綴名都為 **AutoConfiguration

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

3.2.1、getCandidateConfigurations()

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

一步一步點進去:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   // 這里有個 loadFactoryNames 方法 執(zhí)行的時候還傳了兩個參數(shù),一個是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()

接下里又開始調(diào)用 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 在哪里呢?

里面的內(nèi)容:

我們?nèi)粘S玫降?,基本上都有一個配置類。

比如 webmvc,

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

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

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

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

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

這個 factoryTypeName 值為 EnableAutoConfiguration

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

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

看下圖,這不就是嘛?

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

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

那 spring.factories 中存在那么多的配置,每次啟動時都是把它們?nèi)考虞d嗎?

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

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

image-20210927162055644

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

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

這就是SpringBoot的自動配置啦.

四、小結(jié)

簡單總結(jié)起來就是:

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

到此這篇關(guān)于SpringBoot自動配置原理分析的文章就介紹到這了,更多相關(guān)SpringBoot自動配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 取消idea雙擊shift鍵時出現(xiàn)的全局搜索的問題分析

    取消idea雙擊shift鍵時出現(xiàn)的全局搜索的問題分析

    這篇文章主要介紹了取消idea雙擊shift鍵時出現(xiàn)的全局搜索的問題分析,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-10-10
  • @PathVariable為空時指定默認(rèn)值的操作

    @PathVariable為空時指定默認(rèn)值的操作

    這篇文章主要介紹了@PathVariable為空時指定默認(rèn)值的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • SpringBoot使用前綴樹過濾敏感詞的方法實例

    SpringBoot使用前綴樹過濾敏感詞的方法實例

    Trie也叫做字典樹、前綴樹(Prefix Tree)、單詞查找樹,特點:查找效率高,消耗內(nèi)存大,這篇文章主要給大家介紹了關(guān)于SpringBoot使用前綴樹過濾敏感詞的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • Java大文本并行計算實現(xiàn)過程解析

    Java大文本并行計算實現(xiàn)過程解析

    這篇文章主要介紹了Java大文本并行計算如何實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • 詳解Java如何實現(xiàn)在PDF中插入,替換或刪除圖像

    詳解Java如何實現(xiàn)在PDF中插入,替換或刪除圖像

    圖文并茂的內(nèi)容往往讓人看起來更加舒服,如果只是文字內(nèi)容的累加,往往會使讀者產(chǎn)生視覺疲勞。搭配精美的文章配圖則會使文章內(nèi)容更加豐富。那我們要如何在PDF中插入、替換或刪除圖像呢?別擔(dān)心,今天為大家介紹一種高效便捷的方法
    2023-01-01
  • Mybatis-Plus自動填充的實現(xiàn)示例

    Mybatis-Plus自動填充的實現(xiàn)示例

    這篇文章主要介紹了Mybatis-Plus自動填充的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Spring注解之@PropertySource詳解

    Spring注解之@PropertySource詳解

    這篇文章主要介紹了Spring注解之@PropertySource詳解,@PropertySource注解用于指定資源文件讀取的位置,它不僅能讀取properties文件,也能讀取xml文件,并且通過YAML解析器,配合自定義PropertySourceFactory實現(xiàn)解析YAML文件,需要的朋友可以參考下
    2023-11-11
  • springMVC+jersey實現(xiàn)跨服務(wù)器文件上傳

    springMVC+jersey實現(xiàn)跨服務(wù)器文件上傳

    這篇文章主要介紹了springMVC+jersey實現(xiàn)跨服務(wù)器文件上傳,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Springboot2整合knife4j過程解析

    Springboot2整合knife4j過程解析

    這篇文章主要介紹了Springboot2整合knife4j過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • 詳解Spring 兩種注入的方式(Set和構(gòu)造)實例

    詳解Spring 兩種注入的方式(Set和構(gòu)造)實例

    本篇文章主要介紹了Spring 兩種注入的方式(Set和構(gòu)造)實例,Spring框架主要提供了Set注入和構(gòu)造注入兩種依賴注入方式。有興趣的可以了解一下。
    2017-02-02

最新評論