以自动配置DataSource实现为例,分析SpringBoot 的auto-config 机制
自动配置DataSource-向导
SpringBoot 自动配置DataSource,通过 DataSourceAutoConfiguration 实现(约定-XXXAutoConfiguration)。
DataSourceAutoConfiguration 的作用包括:
- 初始化 DataSourceInitializer,该bean 用于运行数据库的初始化脚本( SQL scripts)
- 检测判断条件,引入对应的 DataSource 的实现,委托该实现生成具体的DataSource bean。
其中, DataSource 的实现有3类:PooledDataSourceConfiguration(默认启用)、EmbeddedDataSourceConfiguration、TomcatDataSourceJmxConfiguration
根据配置,优先启用PooledDataSourceConfiguration(@Import 引导具体的实现)。
自动配置DataSource-策略
判定启用的DataSourceConfiguration (实现 DataSource 实例化),策略如下:
- PooledDataSourceConfiguration 引入的判断条件主要依赖 PooledDataSourceCondition 实现,
该 Condition 属于AnyCondition类型(or),通过配置(如下代码)得知,ExplicitType、PooledDataSourceAvailable任意一个条件符合即可。
// 或判断,通过读取当前类的信息,加载多个Condition,进行逻辑判断
static class PooledDataSourceCondition extends AnyNestedCondition {
// 检测是否有配置项 spring.datasource.type
@ConditionalOnProperty(prefix = "spring.datasource", name = "type")
static class ExplicitType {
}
// 检测是否有合适的 连接池实现(比如:当前classloader 包含dbcp、dbcp2、tomcat.jdbc.pool等)
@Conditional(PooledDataSourceAvailableCondition.class)
static class PooledDataSourceAvailable {
}
}
- EmbeddedDataSourceConfiguration 引入的判断条件 与PooledDataSourceConfiguration 互斥
通过EmbeddedDatabaseCondition 配置可以看出 - TomcatDataSourceJmxConfiguration 引入的判断条件满足上述两个的任意一个Condition,并且需要环境中有配置项 spring.datasource.jmx-enabled
通过TomcatDataSourceJmxConfiguration 配置可以看出
自动配置DataSource-实现
- DataSourceConfiguration.Tomcat (默认启用,不做配置,根据加载Class决定)
- DataSourceConfiguration.Hikari
- DataSourceConfiguration.Dbcp
- DataSourceConfiguration.Dbcp2
判定启用的数据库连接池(DataSourcePool),策略如下:
- 首先判断是否加载了对应的实现类,如@ConditionalOnClass(org.apache.commons.dbcp.BasicDataSource.class)
- 然后根据是否有配置项 spring.datasource.type,决定DataSource的实现。默认不指定配置,就根据加载类判断。例如:我们项目中指定spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource,SpringBoot初始化的就是Dbcp2
自动配置DataSource-ConditionalOnProperty
ConditionalOnProperty 单独分析,其余Condition 大体逻辑相同
ConditionalOnProperty 分析:
- 条件判断,通过 OnPropertyCondition 实现功能。
- 检查指定的配置是否具有特定的值。默认情况下,配置项必须存在于环境中,且不等于false
- 允许自定义havingValue()和matchIfMissing()。havingValue指定配置应该具有的值。matchIfMissing 是否允许不存在指定配置项
判断的大体逻辑如下:
private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes, PropertyResolver resolver) {
// 解析Annotation,判断对应的条件归类到missing集合 和 nonMatching集合
spec.collectProperties(resolver, missingProperties, nonMatchingProperties);
// 如果missing集合非空(配置项必须存在于环境,且没有找到),则返回false
if (!missingProperties.isEmpty()) {
return ConditionOutcome.noMatch(...);
}
// 如果nonMatching集合非空(配置项存在于环境,但不是预期值),则返回false
if (!nonMatchingProperties.isEmpty()) {
return ConditionOutcome.noMatch(...);
}
// 返回true
return ConditionOutcome.match(...);
}