在 Spring Boot 中,数据源的自动配置是框架中一个关键功能,本文将以 Spring Boot 2.1.7 版本为例,详细讲解在单数据源情况下数据源是如何自动加载的。我们通过源码分析,追踪整个加载流程。
1. 自动配置类的发现
Spring Boot 使用 spring.factories
机制加载自动配置类。在 org.springframework.boot.autoconfigure
包的 META-INF/spring.factories
文件中,可以找到:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
其中,DataSourceAutoConfiguration
是数据源的自动配置类。
2. DataSourceAutoConfiguration
类
进入 DataSourceAutoConfiguration
类,可以看到其内部有一个静态嵌套类 PooledDataSourceConfiguration
:
@Configuration
@Conditional({PooledDataSourceCondition.class})
@ConditionalOnMissingBean({DataSource.class, XADataSource.class})
@Import({DataSourceConfiguration.Hikari.class,DataSourceConfiguration.Tomcat.class,DataSourceConfiguration.Dbcp2.class,DataSourceConfiguration.Generic.class,DataSourceJmxConfiguration.class
})
protected static class PooledDataSourceConfiguration {protected PooledDataSourceConfiguration() {}
}
关键点解释:
@Conditional
:依赖于PooledDataSourceCondition
判断是否满足条件。@ConditionalOnMissingBean
:确保没有自定义的DataSource
和XADataSource
Bean。@Import
:导入了Hikari
、Tomcat
、Dbcp2
等数据源的配置类。
3. DataSourceConfiguration.Hikari
类
进入 DataSourceConfiguration.Hikari
,这是 HikariCP 数据源的配置类(Tomcat、Dbcp2也类似):
@Configuration
@ConditionalOnClass({HikariDataSource.class})
@ConditionalOnMissingBean({DataSource.class})
@ConditionalOnProperty(name = {"spring.datasource.type"},havingValue = "com.zaxxer.hikari.HikariDataSource",matchIfMissing = true
)
static class Hikari {Hikari() {}@Bean@ConfigurationProperties(prefix = "spring.datasource.hikari")public HikariDataSource dataSource(DataSourceProperties properties) {HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);if (StringUtils.hasText(properties.getName())) {dataSource.setPoolName(properties.getName());}return dataSource;}
}
关键点解释:
@ConditionalOnClass
:确保HikariDataSource
在类路径中存在,即有在pom文件中直接或间接的导入HikariCP依赖。@ConditionalOnMissingBean
:如果没有自己定义其他DataSource
,则会加载此配置。@ConditionalOnProperty
:当在application.yml或application.properties配置文件中spring.datasource.type
的值是HikariDataSource
或未定义时,匹配条件成立,使用 Hikari 数据源。
@ConditionalOnProperty具体用法可以看这篇:@ConditionalOnProperty
4. createDataSource
方法
进入 DataSourceConfiguration.createDataSource
方法:
protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {return properties.initializeDataSourceBuilder().type(type).build();
}
initializeDataSourceBuilder
方法采用了建造者模式对DataSourceBuilder对象进行了属性赋值。具体源码比较简单,大家可以自己点进去看看,要是看不懂可以先去看看建造者模式的文章。
建造者模式可以看这篇文章:建造者模式
5. DataSourceBuilder
的 build
方法
进入build
方法:
public T build() {Class<? extends DataSource> type = this.getType();DataSource result = (DataSource)BeanUtils.instantiateClass(type);this.maybeGetDriverClassName();this.bind(result);return result;
}
关键步骤:
getType
方法:获取数据源的类型。BeanUtils.instantiateClass(type)
:通过反射实例化数据源对象。bind(result)
:将配置信息绑定到数据源对象。
6. getType
方法与默认数据源
在 getType
方法中,当 type
为 null
时,进入 findType
方法:
private Class<? extends DataSource> getType() {Class<? extends DataSource> type = this.type != null ? this.type : findType(this.classLoader);if (type != null) {return type;} else {throw new IllegalStateException("No supported DataSource type found");}
}
findType
方法的实现:
public static Class<? extends DataSource> findType(ClassLoader classLoader) {String[] var1 = DATA_SOURCE_TYPE_NAMES;for (String name : var1) {try {return ClassUtils.forName(name, classLoader);} catch (Exception ignored) {}}return null;
}private static final String[] DATA_SOURCE_TYPE_NAMES = new String[]{"com.zaxxer.hikari.HikariDataSource","org.apache.tomcat.jdbc.pool.DataSource","org.apache.commons.dbcp2.BasicDataSource"
};
关键点解释:
-
默认数据源顺序:
com.zaxxer.hikari.HikariDataSource
(HikariCP)org.apache.tomcat.jdbc.pool.DataSource
(Tomcat 数据源)org.apache.commons.dbcp2.BasicDataSource
(DBCP2 数据源)
-
当
type
为null
时,会按照顺序加载第一个可用的数据源,即 HikariCP。
7. 总结
通过以上分析,可以得出 Spring Boot 数据源自动加载的核心流程:
- 加载自动配置类:通过
spring.factories
加载DataSourceAutoConfiguration
。 - 匹配数据源配置:判断条件,导入
Hikari
、Tomcat
、Dbcp2
等数据源配置类。 - 优先选择 HikariCP:如果未指定
spring.datasource.type
,默认会选择 HikariCP 作为数据源。 - 数据源初始化:通过
DataSourceBuilder
使用责任链模式构建数据源对象。
8. 源码阅读建议
在阅读 Spring Boot 源码时,版本差异可能会导致配置逻辑有所不同,因此:
- 尽量选择与项目中一致的 Spring Boot 版本。
- 使用调试工具,逐步跟踪代码执行流程,理解自动配置的细节。
希望本文能帮助大家更好地理解 Spring Boot 2.1.7 数据源自动加载的过程,也欢迎大家在评论区留言,一起交流学习!