簡單詳細的SpringBoot自動配置原理解析

文章目錄

    前言
    環(huán)境
    從啟動類開始
        @SpringBootApplication
        @EnableAutoConfiguration
        AutoConfigurationImportSelector的selectImports方法
        配置類注冊到IOC容器的流程圖
    以DataSourceAutoConfiguration進行說明
        DataSourceProperties 類
        DataSourcePoolMetadataProvidersConfiguration 類
    總結

前言

上一篇文章我們介紹了SpringFactoriesLoader,之所以介紹SpringFactoriesLoader是因為我們這篇文章要介紹的SpringBoot的自動配置會用到SpringFactoriesLoader的知識。閑話少敘,讓我們直入主題。
環(huán)境

spring-boot 1.5.8.RELEASE
從啟動類開始

@SpringBootApplication
public class HelloworldDemoApplication {

public static void main(String[] args) {
    SpringApplication.run(HelloworldDemoApplication.class, args);
}

}

如上,就是我們SpringBoot應用的啟動類。讓我們把眼光聚焦到@SpringBootApplication注解上面。這個注解是SpringBoot項目的主配置類。
@SpringBootApplication

//省略部分注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}

根據(jù)前幾篇的介紹,我們可以知道@SpringBootApplication注解是一個組合注解。
@SpringBootConfiguration注解 表示這是SpringBoot的配置類,
@ComponentScan 開啟組件掃描
@EnableAutoConfiguration這個注解的作用就是讓SpringBoot開啟自動配置。自動配置的奧秘全都在這里:
@EnableAutoConfiguration

//省略部分注解
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

}

如上我們可以看到EnableAutoConfiguration注解上有兩個注解

@AutoConfigurationPackage 注解,
從字面意思上來看就是自動配置包。點進去可以看到就是?個 @Import 注解: @Import(AutoConfigurationPackages.Registrar.class) ,導?了?個
Registrar 的組件,這個注解的作用就是將主配置類(@SpringBootConfiguration標注的類)所在的包及其下面所有子包里面所有的組件掃描到IOC容器中。所以說,默認情況下主配置類所在包及其子包以外的組件,Spring IOC容器是掃描不到的。
@Import(AutoConfigurationImportSelector.class)
通過@Import導入了AutoConfigurationImportSelector類,而這個類的selectImports方法會通過SpringFactoriesLoader得到大量的配置類。而每個配置類則根據(jù)條件化配置類做出決策,以實現(xiàn)自動配置的功能。下面就讓我們來看看selectImports方法。

AutoConfigurationImportSelector的selectImports方法

public String[] selectImports(AnnotationMetadata annotationMetadata) {
	//省略部分代碼
	List<String> configurations = getCandidateConfigurations(annotationMetadata,
			attributes);
	return StringUtils.toStringArray(configurations);
}

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
		AnnotationAttributes attributes) {
		
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
			getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
	return configurations;
}

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

如上代碼,自動配置核心的代碼我都羅列出來了,最核心的就是loadFactoryNames方法,其主要有三步:

從classpath下獲取所有META-INF/spring.factories這個文件下的信息。
將上面獲取到的信息封裝成Enumeration返回
遍歷Enumeration,然后獲取key為EnableAutoConfiguration下的所有值。
META-INF/spring.factories 這類?件是什么就不懵了。當然在很多第三?依賴中
都會有這個?件,?般每導??個第三?的依賴,除了本?的jar包以外,還會有?個 xxx-spring-boot-autoConfigure,這個就
是第三?依賴??編寫的?動配置類。我們現(xiàn)在就以 spring-boot-autocongigure 這個依賴來說下,其下面的META-INF/spring.factories文件。

Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\

配置類注冊到IOC容器的流程圖

然后就是實例化這些配置類注冊到IOC容器中。流程如下:

以DataSourceAutoConfiguration進行說明

通過上面的方式,所有的自動配置類都被導進主配置類中,但是這么多的配置類,明顯有很多我們平常是沒有使用到的,沒必要全部生效,下面我們以DataSourceAutoConfiguration配置類為例來看一下自動配置類是如何工作的:

@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {

}


@Configuration 注解表明了DataSourceAutoConfiguration類是一個JavaConfig配置類。@ConditionalOnClass只有當classpath中存在DataSource類或者EmbeddedDatabaseType類時才啟動這個配置。@EnableConfigurationProperties這個注解的作用是將將DataSource類注入到IOC容器中。@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })是要導入額外的配置DataSourcePoolMetadataProvidersConfiguration。
DataSourceProperties 類

下面我們就來一個個看一下:首先是DataSourceProperties類:

@ConfigurationProperties(prefix = “spring.datasource”)
public class DataSourceProperties
implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {

private ClassLoader classLoader;

private Environment environment;

private String name = "testdb";


private boolean generateUniqueName;


private Class<? extends DataSource> type;


private String driverClassName;

private String url;

}

DataSourceProperties 通過@ConfigurationProperties注解將配置文件的前綴為(spring.datasource)的配置信息與自身的屬性綁定。所有在配置?件中能配置的屬性都是在 xxxProperties 類中封裝著;配置?件能配置什么就可以參照某個功能對應的這個屬性
類。
DataSourcePoolMetadataProvidersConfiguration 類

@Configuration
public class DataSourcePoolMetadataProvidersConfiguration {

@Configuration
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
static class TomcatDataSourcePoolMetadataProviderConfiguration {
}

@Configuration
@ConditionalOnClass(HikariDataSource.class)
static class HikariPoolDataSourceMetadataProviderConfiguration {

DataSourcePoolMetadataProvidersConfiguration 類是數(shù)據(jù)庫連接池提供者的一個配置類。即classpath中存在org.apache.tomcat.jdbc.pool.DataSource.class則使?tomcat-jdbc連接池,如果classpath中存在 HikariDataSource.class則使? Hikari連接池,如果存在org.apache.commons.dbcp.BasicDataSource.class則啟用dbcp 連接池。
總結

SpringBoot啟動時會掃描項目所依賴的JAR包,尋找包含spring.factories文件的JAR包。
根據(jù)spring.factories配置加載EnableAutoConfiguration
其中給容器中自動配置添加組件的時候,會從propeties類中獲取配置文件中指定這些屬性的值。xxxAutoConfiguration:?動配置類給容器中添加組件。xxxProperties:封裝配置?件中相關屬性。
根據(jù)@Conditional注解的條件,進行自動配置并將Bean注入Spring容器




作者:碼農(nóng)飛哥
微信公眾號:碼農(nóng)飛哥