SpringBoot自動配置原理

菜鳥全棧BeeStack發表於2021-10-21

SpringBoot自動配置原理

本節主要分析:

  • 核心註解SpringBootApplication註解
  • EnableAutoConfiguration自動配置的原始碼分析

1 SpringBootApplication註解

@SpringBootApplication,標識某個類上說明這個類是 SpringBorn的主配置類。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication

1.1 @ SpringBootConfiguration: Spring Boot的配置類

標註在某個類上,表示這是一個 Spring boot的配置類;

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

@ Configuration配罩類上來標註這個註解; 配置類---配置檔案。配置類,本質上也是容器中的一個元件;@ Component

1.2 @ EnableAutoConfiguration:開啟自動配置功能

以前我們需要配置的東西, Spring boot幫我們自動配置;@ EnableAuto Configuration告訴Springboot開啟自動配置功能:這樣自動配置才能生效。

@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:自動配置包

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

@Import({Registrar.class})

Spring的底層註解@Import,給容器中匯入一個元件;匯入的元件由AutoConfigurationPackages. Registrar. class

主要作用是:將主配置類(@ Spring BootApplicationa標註的類)的所在包及下面所有子包裡面的所有元件掃描到 Spring容器

image

@Import({AutoConfigurationImportSelector.class}) 給容器匯入元件。

AutoConfigurationImportSelector :匯入哪些元件的選擇器。將所有需要匯入的元件以全類名的方式返回;這些元件就會被新增到容器中。會給容器中匯入非常多的自動配置類( XXXAutoConfiguration),並配置號這些元件。

image

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   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;
}

Spring Boot在啟動的時候從類路徑下的 META-INF/spring.factories中獲取 EnableAutoConfiguration指定的值,將這些值封裝成Properties物件,並返回給載入器。

image

而外部傳入的class是EnableAutoConfiguration.class,也就是說從 properties中獲取到EnableAutoConfiguration.class類對應的很多配置載入到容器中,每個配置都是自動配置類xxxAutoConfigration。每個Configuration類作為容器的元件載入到容器中,進行自動配置。

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader)

以HttpEncodingAutoConfiguration為例,自動配置類上有多個註解。所有配置類的屬性都在xxProperties類中封裝,配置類配置了什麼功能可以參考屬性檔案。

// 標識配置類
@Configuration
// 啟用ConfigurationProperties功能呢,繫結HttpProperties屬性類,注入到IOC容器中
@EnableConfigurationProperties(HttpProperties.class)
// conditional是spring底層註解,滿足指定條件,則配置類中的配置才會生效
// 本例中是滿足web應用時,配置生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
// 判斷是否有CharacterEncodingFilter過濾器
@ConditionalOnClass(CharacterEncodingFilter.class)
// 判斷是否存在某個配置spring.http.encoding.enabled,如果沒有配置這條屬性,預設生效
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
    private final HttpProperties.Encoding properties;

    // 指定使用HttpProperties中的Encoding屬性
	public HttpEncodingAutoConfiguration(HttpProperties properties) {
		this.properties = properties.getEncoding();
	}

    // 返回Bean,使用properties
	@Bean
	@ConditionalOnMissingBean
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
		return filter;
	}
}

如果AutoConfiguration類的所有條件都滿足,就會執行自動配置,建立Bean注入到容器中。由此可見,META-INF/spring.factories的EnableAutoConfiguration屬性配置了很多自動配置類名,並不是所有的都生效。

一但這個配置類生效;這個配置類就會給容器中新增各種元件:這些元件的屬性是從對應的 properties類中獲取的,這些類裡面的每一個屬性又是和配置檔案繫結的。我們在專案配置檔案中能配置下面的屬性,屬性來源主要是HttpProperties屬性繫結類。

spring.http.encoding.enabled=true
spring.http.encoding.charset=utf-8
spring.http.encoding.force=true

J2E的整體整合解決方案和自動配置都在 spring-boot-autoconfigure-2.XX. RELEASE. jar;

SpringBoot自動配置的總結與運用

SpringBoot啟動時會載入大量自動配置類,我們根據需要的功能檢視springboot是否預設自動配置,如果用到的元件已經載入,就不用自己配置了。springboot自動配置類新增元件時,會從properties類中獲取某些屬性。如果對這些預設屬性不滿意,可以在專案配置檔案中自定義配置。

@ Conditional派生註解( spring註解版原生的@Conditional作用)

作用:必須是@Conditional指定的條件成立,才給容器中新增元件,配置配裡面的所有內容才生效。自動配置類必須在一定條件下才生效,例如上面的HttpEncodingAutoConfiguration自動配置類必須滿足是web應用,具有編碼過濾器,並且沒有該bean時才生成。

然而,如果對於每個配置類都要挨個查是否生效配置,效率太差。我們可以啟動springboot的debug屬性,在控制檯列印自動配置報告。

debug:
	true

Positive matches:生效
Negative matches:未生效

相關文章