Blogger Information
Blog 41
fans 0
comment 0
visits 25190
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
25、【网摘】Spring Boot数据源配置原理
自由之上
Original
504 people have browsed it

在数据库访问过程中,“数据源”无疑是最重要的概念之一,它不仅可以对与数据库访问相关的各种参数进行封装和统一管理,还可以管理数据库连接池,提高数据库连接性能。

目前,在市面上有很多优秀的开源数据源,例如 DBCP、C3P0、Druid、HikariCP 等等。在 Spring Boot 2.x 中,则采用目前性能最佳的 HikariCP 作为其默认数据源。接下来,我们就来具体介绍下 Spring Boot 的默认数据源配置及其原理。

1、DataSourceAutoConfiguration

我们知道,Spring Boot 中几乎所有的默认配置都是通过配置类 XxxAutoConfiguration 进行配置的,Spring Boot 数据源也不例外,它的自动配置类是:DataSourceAutoConfiguration。

DataSourceAutoConfiguration 中 共包括以下 5 个内部静态类:

  • EmbeddedDatabaseCondition
  • PooledDataSourceAvailableCondition
  • PooledDataSourceCondition
  • PooledDataSourceConfiguration(池化数据源自动配置类)
  • EmbeddedDatabaseConfiguration(内嵌数据源自动配置类)

其中,PooledDataSourceConfiguration 和 EmbeddedDatabaseConfiguration 为使用了 @Configuration 注解的自动配置类,其余 3 个为限制条件类。

1、EmbeddedDatabaseConfiguration

顾名思义,EmbeddedDatabaseConfiguration 是内嵌数据源的自动配置类,该类中并没有任何的方法实现,它的主要功能都是通过 @Import 注解引入 EmbeddedDataSourceConfiguration 类来实现的。

  1. @Import({EmbeddedDataSourceConfiguration.class})

EmbeddedDataSourceConfiguration 向容器中添加了一个 Spring Boot 内嵌的数据源,该数据源支持 HSQL,H2 和 DERBY 三种数据库,其部分代码如下。

  1. @Configuration(proxyBeanMethods = false)
  2. @EnableConfigurationProperties({DataSourceProperties.class})
  3. public class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware {
  4. private ClassLoader classLoader;
  5. public EmbeddedDataSourceConfiguration() {
  6. }
  7. public void setBeanClassLoader(ClassLoader classLoader) {
  8. this.classLoader = classLoader;
  9. }
  10. //向容器中添加 Spring Boot 内嵌的数据源
  11. @Bean(
  12. destroyMethod = shutdown
  13. )
  14. public EmbeddedDatabase dataSource(DataSourceProperties properties) {
  15. return (new EmbeddedDatabaseBuilder()).setType(EmbeddedDatabaseConnection.get(this.classLoader).getType()).setName(properties.determineDatabaseName()).build();
  16. }
  17. }

通过上面的分析,我们知道自动配置类 EmbeddedDatabaseConfiguration 的作用是向容器中添加一个内嵌的数据源(DataSource),但这是有条件限制的。

在 EmbeddedDatabaseConfiguration 类上还使用一个 @Conditional 注解,该注解使用了 DataSourceAutoConfiguration 的内部限制条件类 EmbeddedDatabaseCondition 来进行条件判断。

  1. @Conditional({DataSourceAutoConfiguration.EmbeddedDatabaseCondition.class})

EmbeddedDatabaseCondition 主要用来检测容器中是否已经存在池化数据源(PooledDataSource)。若容器中存在池化数据源时,则 EmbeddedDatabaseConfiguration 不能被实例化。只有当容器中不存在池化数据源时,EmbeddedDatabaseConfiguration 才能被实例化,才能向容器中添加内嵌数据源(EmbeddedDataSource)。

2、PooledDataSourceConfiguration

PooledDataSourceConfiguration 是池化数据源的自动配置类,该类上使用了一个 @Conditional 注解,该注解使用了 DataSourceAutoConfiguration 的内部限制条件类 PooledDataSourceCondition 来进行条件判断。

  1. @Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class})

PooledDataSourceCondition 与 EmbeddedDatabaseCondition 一样,也是用来检测容器中是否已经存在池化数据源的,但不同的是,PooledDataSourceConfiguration 是只有当容器中存在池化数据源时, 才可以被实例化,才可以向容器中添加池化数据源。

与 EmbeddedDatabaseConfiguration 一样,PooledDataSourceConfiguration 类中也没有任何的方法实现,它的所有功能都是通过 @Import 注解引入其他的类实现的。

  1. @Import({Hikari.class, Tomcat.class, Dbcp2.class, OracleUcp.class, Generic.class, DataSourceJmxConfiguration.class})

PooledDataSourceConfiguration 通过 @Import 注解引入了 Hikari、Tomcat、Dbcp2、OracleUcp 和 Generic 五个数据源配置类,它们都是 DataSourceConfiguration 的内部类,且它们的功能类似,都是向容器中添加指定的数据源。

下面我们以 Hikari 为例进行分析,Hikari 的源码如下。

  1. @Configuration(
  2. proxyBeanMethods = false
  3. )
  4. @ConditionalOnClass({HikariDataSource.class})
  5. @ConditionalOnMissingBean({DataSource.class})
  6. @ConditionalOnProperty(
  7. name = {“spring.datasource.type”},
  8. havingValue = com.zaxxer.hikari.HikariDataSource”,
  9. matchIfMissing = true
  10. )
  11. static class Hikari {
  12. Hikari() {
  13. }
  14. @Bean
  15. @ConfigurationProperties(
  16. prefix = spring.datasource.hikari
  17. )
  18. HikariDataSource dataSource(DataSourceProperties properties) {
  19. HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
  20. if (StringUtils.hasText(properties.getName())) {
  21. dataSource.setPoolName(properties.getName());
  22. }
  23. return dataSource;
  24. }
  25. }

在 Hikari 类中,主要使用以下注解:

  • @Configuration:表示当前类是一个配置类;
  • @ConditionalOnMissingBean({DataSource.class}):表示容器中没有用户自定义的数据源时,该配置类才会被实例化;
  • @ConditionalOnClass({HikariDataSource.class}) :表示必须在类路径中存在 HikariDataSource 类时,Hikari 才会实例化。而 HikariDataSource 类是由 spring- boot-starter-jdbc 默认将其引入的,因此只要我们在 pom.xml 中引入了该 starter, Hikari 就会被实例化(这也是 Spring Boot 2.x 默认使用 HikariCP 作为其数据源的原因)。;
  • @ConditionalOnProperty( name = {“spring.datasource.type”},havingValue = “com.zaxxer.hikari.HikariDataSource”,matchIfMissing = true): 表示当 Spring Boot 配置文件中,配置了 spring.datasource.type = com.zaxxer.hikari.HikariDataSource(明确指定使用 Hikari 数据源)或者不配置 spring.datasource.type(即默认情况)时,Hikari 才会被实例化。

Hikari 类通过 @Bean 注解向容器中添加了 HikariDataSource 组件,该组件的实例对象是通过调用 DataSourceConfiguration 的 createDataSource() 方法得到的,代码如下。

  1. @Bean
  2. @ConfigurationProperties(
  3. prefix = spring.datasource.hikari
  4. )
  5. HikariDataSource dataSource(DataSourceProperties properties) {
  6. HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
  7. if (StringUtils.hasText(properties.getName())) {
  8. dataSource.setPoolName(properties.getName());
  9. }
  10. return dataSource;
  11. }

在 createDataSource() 方法中,调用 DataSourceProperties 的 initializeDataSourceBuilder() 来初始化 DataSourceBuilder,源码如下。

  1. protected static T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
  2. return properties.initializeDataSourceBuilder().type(type).build();
  3. }

initializeDataSourceBuilder() 方法通过调用 DataSourceBuilder 的 create() 方法创建 DataSourceBuilder 对象,并根据 Spring Boot 的配置文件(application.properties/yml)中的配置,依次设置数据源类型、驱动类名、连接 url、 用户名和密码等信息。

  1. public DataSourceBuilder<?> initializeDataSourceBuilder() {
  2. return DataSourceBuilder.create(this.getClassLoader()).type(this.getType()).
  3. driverClassName(this.determineDriverClassName()).url(this.determineUrl()).username(this.determineUsername()).password(this.determinePassword());
  4. }

上面提到 spring.datasource.type 默认是可以不用配置的,因此在 createDataSource() 方法在获取到回传回来的 DataSourceBuilder 对象后,还需要将其 type 属性再次设置为 HikariDataSource,并调用 DataSourceBuilder 的 build() 方法,完成 HikariDataSource 的初始化。

图1:初始化 HikariDataSource

dataSource() 方法获得数据源对象,并设置了连接池的名字(name),注入到容器中。

图2:设置连接池 name

自此,我们就完成了对 Spring Boot 数据源自动配置原理的分析。

总结

通过对 Spring Boot 数据源自动配置原理的分析可知:
在用户没有配置数据源的情况,若容器中存在 HikariDataSource 类,则 Spring Boot 就会自动实例化 Hikari,并将其作为其数据源。

Spring Boot 的 JDBC 场景启动器(spring-boot-starter-data-jdbc)通过 spring- boot-starter-jdbc 默认引入了 HikariCP 数据源(包含 HikariDataSource 类),因此 Spring Boot 默认使用 HikariCP 作为其数据源。


加入
QQ群:722461036
微信群:
一起督促、学习、练习、温习、复习 ~ ~ ~

Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!