簡單詳細(xì)的SpringBoot自動(dòng)配置原理解析
文章目錄
前言
上一篇文章我們介紹了SpringFactoriesLoader
,之所以介紹SpringFactoriesLoader
是因?yàn)槲覀冞@篇文章要介紹的SpringBoot的自動(dòng)配置會(huì)用到SpringFactoriesLoader
的知識(shí)。閑話少敘,讓我們直入主題。
環(huán)境
spring-boot 1.5.8.RELEASE
從啟動(dòng)類開始
@SpringBootApplication
public class HelloworldDemoApplication {
public static void main(String[] args) {
SpringApplication.run(HelloworldDemoApplication.class, args);
}
}
如上,就是我們SpringBoot應(yīng)用的啟動(dòng)類。讓我們把眼光聚焦到@SpringBootApplication
注解上面。這個(gè)注解是SpringBoot項(xiàng)目的主配置類。
@SpringBootApplication
//省略部分注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
根據(jù)前幾篇的介紹,我們可以知道@SpringBootApplication
注解是一個(gè)組合注解。
@SpringBootConfiguration
注解 表示這是SpringBoot的配置類,
@ComponentScan
開啟組件掃描
@EnableAutoConfiguration
這個(gè)注解的作用就是讓SpringBoot開啟自動(dòng)配置。自動(dòng)配置的奧秘全都在這里:
@EnableAutoConfiguration
//省略部分注解
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
如上我們可以看到EnableAutoConfiguration
注解上有兩個(gè)注解
@AutoConfigurationPackage
注解,
從字面意思上來看就是自動(dòng)配置包。點(diǎn)進(jìn)去可以看到就是?個(gè)@Import
注解:@Import(AutoConfigurationPackages.Registrar.class)
,導(dǎo)?了?個(gè)
Registrar 的組件,這個(gè)注解的作用就是將主配置類(@SpringBootConfiguration
標(biāo)注的類)所在的包及其下面所有子包里面所有的組件掃描到IOC容器中。所以說,默認(rèn)情況下主配置類所在包及其子包以外的組件,Spring IOC容器是掃描不到的。@Import(AutoConfigurationImportSelector.class)
通過@Import
導(dǎo)入了AutoConfigurationImportSelector
類,而這個(gè)類的selectImports
方法會(huì)通過SpringFactoriesLoader
得到大量的配置類。而每個(gè)配置類則根據(jù)條件化配置類做出決策,以實(shí)現(xiàn)自動(dòng)配置的功能。下面就讓我們來看看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;
}
如上代碼,自動(dòng)配置核心的代碼我都羅列出來了,最核心的就是loadFactoryNames
方法,其主要有三步:
- 從classpath下獲取所有
META-INF/spring.factories
這個(gè)文件下的信息。 - 將上面獲取到的信息封裝成Enumeration返回
- 遍歷Enumeration,然后獲取key為
EnableAutoConfiguration
下的所有值。
META-INF/spring.factories
這類?件是什么就不懵了。當(dāng)然在很多第三?依賴中
都會(huì)有這個(gè)?件,?般每導(dǎo)??個(gè)第三?的依賴,除了本?的jar包以外,還會(huì)有?個(gè) xxx-spring-boot-autoConfigure,這個(gè)就
是第三?依賴??編寫的?動(dòng)配置類。我們現(xiàn)在就以 spring-boot-autocongigure 這個(gè)依賴來說下,其下面的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,\
配置類注冊(cè)到IOC容器的流程圖
然后就是實(shí)例化這些配置類注冊(cè)到IOC容器中。流程如下:
以DataSourceAutoConfiguration進(jìn)行說明
通過上面的方式,所有的自動(dòng)配置類都被導(dǎo)進(jìn)主配置類中,但是這么多的配置類,明顯有很多我們平常是沒有使用到的,沒必要全部生效,下面我們以DataSourceAutoConfiguration
配置類為例來看一下自動(dòng)配置類是如何工作的:
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
}
@Configuration
注解表明了DataSourceAutoConfiguration
類是一個(gè)JavaConfig配置類。@ConditionalOnClass
只有當(dāng)classpath中存在DataSource
類或者EmbeddedDatabaseType
類時(shí)才啟動(dòng)這個(gè)配置。@EnableConfigurationProperties
這個(gè)注解的作用是將將DataSource
類注入到IOC容器中。@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
是要導(dǎo)入額外的配置DataSourcePoolMetadataProvidersConfiguration
。
DataSourceProperties 類
下面我們就來一個(gè)個(gè)看一下:首先是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 類中封裝著;配置?件能配置什么就可以參照某個(gè)功能對(duì)應(yīng)的這個(gè)屬性
類。
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ù)庫連接池提供者的一個(gè)配置類。即classpath中存在org.apache.tomcat.jdbc.pool.DataSource.class
則使?tomcat-jdbc連接池,如果classpath中存在 HikariDataSource.class則使? Hikari連接池,如果存在org.apache.commons.dbcp.BasicDataSource.class
則啟用dbcp 連接池。
總結(jié)
- SpringBoot啟動(dòng)時(shí)會(huì)掃描項(xiàng)目所依賴的JAR包,尋找包含spring.factories文件的JAR包。
- 根據(jù)spring.factories配置加載EnableAutoConfiguration
其中給容器中自動(dòng)配置添加組件的時(shí)候,會(huì)從propeties
類中獲取配置文件中指定這些屬性的值。xxxAutoConfiguration:?動(dòng)配置類給容器中添加組件。xxxProperties:封裝配置?件中相關(guān)屬性。 - 根據(jù)@Conditional注解的條件,進(jìn)行自動(dòng)配置并將Bean注入Spring容器
作者:碼農(nóng)飛哥
微信公眾號(hào):碼農(nóng)飛哥
