簡單詳細的SpringBoot自動配置原理解析
文章目錄
前言
上一篇文章我們介紹了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應(yīng)用的啟動類。讓我們把眼光聚焦到@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)
,導(dǎo)?了?個
Registrar 的組件,這個注解的作用就是將主配置類(@SpringBootConfiguration
標(biāo)注的類)所在的包及其下面所有子包里面所有的組件掃描到IOC容器中。所以說,默認(rèn)情況下主配置類所在包及其子包以外的組件,Spring IOC容器是掃描不到的。@Import(AutoConfigurationImportSelector.class)
通過@Import
導(dǎo)入了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
這類?件是什么就不懵了。當(dāng)然在很多第三?依賴中
都會有這個?件,?般每導(dǎo)??個第三?的依賴,除了本?的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進行說明
通過上面的方式,所有的自動配置類都被導(dǎo)進主配置類中,但是這么多的配置類,明顯有很多我們平常是沒有使用到的,沒必要全部生效,下面我們以DataSourceAutoConfiguration
配置類為例來看一下自動配置類是如何工作的:
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
}
@Configuration
注解表明了DataSourceAutoConfiguration
類是一個JavaConfig配置類。@ConditionalOnClass
只有當(dāng)classpath中存在DataSource
類或者EmbeddedDatabaseType
類時才啟動這個配置。@EnableConfigurationProperties
這個注解的作用是將將DataSource
類注入到IOC容器中。@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
是要導(dǎo)入額外的配置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 類中封裝著;配置?件能配置什么就可以參照某個功能對應(yīng)的這個屬性
類。
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 連接池。
總結(jié)
- SpringBoot啟動時會掃描項目所依賴的JAR包,尋找包含spring.factories文件的JAR包。
- 根據(jù)spring.factories配置加載EnableAutoConfiguration
其中給容器中自動配置添加組件的時候,會從propeties
類中獲取配置文件中指定這些屬性的值。xxxAutoConfiguration:?動配置類給容器中添加組件。xxxProperties:封裝配置?件中相關(guān)屬性。 - 根據(jù)@Conditional注解的條件,進行自動配置并將Bean注入Spring容器
作者:碼農(nóng)飛哥
微信公眾號:碼農(nóng)飛哥