springboot_自動配置原理

目錄

  • 1.1 @SpringBootApplication
  • 2.1 @EnableAutoConfiguration
    • 2.1.1 @AutoConfigurationPackage
    • 2.1.2 @Import({Registrar.class})
  • 3.1 以HttpEncodingAutoConfiguration為例

springboot啥都不難,總所周知spring全家桶系列難就難在理解源碼。。。。。。。

今天結合網上資料,自己總結了一下springboot的自動配置原理。

我現在使用的springboot版本為2.3.1.不同版本的springboot在源碼上有差別!但大體一致。

管他三七二十一先打個斷點再說:

1.1 @SpringBootApplication

這個註解點進去我們可以看到:

這裏面主要關注兩個東西:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
    第一個註解點進去:

    可以看到這個@SpringBootConfiguration本質就是一個@Configuration,標註在某個類上,表示這是一個Spring Boot的配置類。
    第二個註解@EnableAutoConfiguration: 開啟自動配置類,SpringBoot的精華所在。(最重要的就是這個註解)

2.1 @EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

兩個比較重要的註解:

  • @AutoConfigurationPackage:自動配置包。
  • @Import({AutoConfigurationImportSelector.class}):導入自動配置的組件。

2.1.1 @AutoConfigurationPackage

點進去瞅瞅:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

發現這裡有導入Regitstrar類:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

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

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }

new PackageImport(metadata).getPackageName(),它其實返回了當前主程序類的 **同級以及子級 ** 的包組件。

什麼意思呢?

我們來看這樣一個目錄:

bean1和我們的springboot啟動類位於同一個包下,二bean2不是位於我們啟動類的同級目錄或者子級目錄,那麼我們啟動的時候bean2是不會被加載到的!所以你項目的一切需要加入容器的類必須放在啟動類的同級包下或者它的子級目錄中。

2.1.2 @Import({Registrar.class})

AutoConfigurationImportSelector有一個方法為:selectImports。

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

它首先回去檢查是否開啟了自動配置類,然後才回去加載註解數據 this.getAutoConfigurationEntry(annotationMetadata);
那麼這個annotationMetadata在哪兒?
來看下面一行代碼:

  protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }

SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
再點進去我們會發現這一行代碼:
Enumeration urls = classLoader != null ? classLoader.getResources(“META-INF/spring.factories”) : ClassLoader.getSystemResources(“META-INF/spring.factories”);

它其實是去加載 public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”;外部文件。這個外部文件,有很多自動配置的類。如下:

spring.factories文件由一組一組的key=value的形式,其中一個key是EnableAutoConfiguration類的全類名,而它的value是一個xxxxAutoConfiguration的類名的列表,這些類名以逗號分隔。
springboot項目啟動時,@SpringBootApplication用在啟動類在SpringApplication.run(…)的內部就會執行selectImports()方法,找到所有JavaConfig自動配置類的全限定名對應的class,然後將所有自動配置類加載到Spring容器中。

3.1 以HttpEncodingAutoConfiguration為例

@Configuration(
    proxyBeanMethods = false
)    //表示是一個配置類,可以給容器中添加組件
@EnableConfigurationProperties({ServerProperties.class})// 啟用ConfigurationProperties功能
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
    prefix = "server.servlet.encoding",
    value = {"enabled"},
    matchIfMissing = true
)

@EnableConfigurationProperties({ServerProperties.class})// 啟用ConfigurationProperties功能
ServerProperties.class:

@ConfigurationProperties(
    prefix = "server",
    ignoreUnknownFields = true
)

@ConditionalOnWebApplication :spring底層@Conditional註解,根據不同的條件進行判斷,如果滿足條件整個配置類才會生效。

總結:
1.springboot會自動加載大量的自動配置類。
2.只要我們要用的組件有,我們就不需要再去配置
3.給容器添加組件的時候。會從properties類中獲取某些屬性。我們就可以在配置文件中指定這些屬性。
xxxxxAutoConfiguration:自動配置類

給容器中添加屬性:
xxxxProperties:封裝配置文件中的相關屬性。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

新北清潔公司,居家、辦公、裝潢細清專業服務

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

您可能也會喜歡…