Java | Spring Boot数据源配置原理
在数据库访问过程中,“数据源”无疑是最重要的概念之一,它不仅可以对与数据库访问相关的各种参数进行封装和统一管理,还可以管理数据库连接池,提高数据库连接性能。
目前,在市面上有很多优秀的开源数据源,例如 DBCP、C3P0、Druid、HikariCP 等等。在 Spring Boot 2.x 中,则采用目前性能最佳的 HikariCP 作为其默认数据源。接下来,我们就来具体介绍下 Spring Boot 的默认数据源配置及其原理。
DataSourceAutoConfiguration
我们知道,Spring Boot 中几乎所有的默认配置都是通过配置类 XxxAutoConfiguration 进行配置的,Spring Boot 数据源也不例外,它的自动配置类是:DataSourceAutoConfiguration。
DataSourceAutoConfiguration 中共包括以下 5 个内部静态类:
- EmbeddedDatabaseCondition
- PooledDataSourceAvailableCondition
- PooledDataSourceCondition
- PooledDataSourceConfiguration(池化数据源自动配置类)
- EmbeddedDatabaseConfiguration(内嵌数据源自动配置类)
其中,PooledDataSourceConfiguration 和 EmbeddedDatabaseConfiguration 为使用了 @Configuration 注解的自动配置类,其余 3 个为限制条件类。
EmbeddedDatabaseConfiguration
顾名思义,EmbeddedDatabaseConfiguration 是内嵌数据源的自动配置类,该类中并没有任何的方法实现,它的主要功能都是通过 @Import 注解引入 EmbeddedDataSourceConfiguration 类来实现的。
@Import({EmbeddedDataSourceConfiguration.class})
EmbeddedDataSourceConfiguration 向容器中添加了一个 Spring Boot 内嵌的数据源,该数据源支持 HSQL,H2 和 DERBY 三种数据库,其部分代码如下。
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({DataSourceProperties.class})
public class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware {
private ClassLoader classLoader;
public EmbeddedDataSourceConfiguration() {
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
//向容器中添加 Spring Boot 内嵌的数据源
@Bean(
destroyMethod = "shutdown"
)
public EmbeddedDatabase dataSource(DataSourceProperties properties) {
return (new EmbeddedDatabaseBuilder()).setType(EmbeddedDatabaseConnection.get(this.classLoader).getType()).setName(properties.determineDatabaseName()).build();
}
}
通过上面的分析,我们知道自动配置类 EmbeddedDatabaseConfiguration 的作用是向容器中添加一个内嵌的数据源(DataSource),但这是有条件限制的。
在 EmbeddedDatabaseConfiguration 类上还使用一个 @Conditional 注解,该注解使用了 DataSourceAutoConfiguration 的内部限制条件类 EmbeddedDatabaseCondition 来进行条件判断。
@Conditional({DataSourceAutoConfiguration.EmbeddedDatabaseCondition.class})
EmbeddedDatabaseCondition 主要用来检测容器中是否已经存在池化数据源(PooledDataSource)。若容器中存在池化数据源时,则 EmbeddedDatabaseConfiguration 不能被实例化。只有当容器中不存在池化数据源时,EmbeddedDatabaseConfiguration 才能被实例化,才能向容器中添加内嵌数据源(EmbeddedDataSource)。
PooledDataSourceConfiguration
PooledDataSourceConfiguration 是池化数据源的自动配置类,该类上使用了一个 @Conditional 注解,该注解使用了 DataSourceAutoConfiguration 的内部限制条件类 PooledDataSourceCondition 来进行条件判断。
@Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class})
PooledDataSourceCondition 与 EmbeddedDatabaseCondition 一样,也是用来检测容器中是否已经存在池化数据源的,但不同的是,PooledDataSourceConfiguration 是只有当容器中存在池化数据源时, 才可以被实例化,才可以向容器中添加池化数据源。
与 EmbeddedDatabaseConfiguration 一样,PooledDataSourceConfiguration 类中也没有任何的方法实现,它的所有功能都是通过 @Import 注解引入其他的类实现的。
@Import({Hikari.class, Tomcat.class, Dbcp2.class, OracleUcp.class, Generic.class, DataSourceJmxConfiguration.class})
PooledDataSourceConfiguration 通过 @Import 注解引入了 Hikari、Tomcat、Dbcp2、OracleUcp 和 Generic 五个数据源配置类,它们都是 DataSourceConfiguration 的内部类,且它们的功能类似,都是向容器中添加指定的数据源。
下面我们以 Hikari 为例进行分析,Hikari 的源码如下。
@Configuration(
proxyBeanMethods = false
)
@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"
)
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
在 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() 方法得到的,代码如下。
@Bean
@ConfigurationProperties(
prefix = "spring.datasource.hikari"
)
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
在 createDataSource() 方法中,调用 DataSourceProperties 的 initializeDataSourceBuilder() 来初始化 DataSourceBuilder,源码如下。
protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
return properties.initializeDataSourceBuilder().type(type).build();
}
initializeDataSourceBuilder() 方法通过调用 DataSourceBuilder 的 create() 方法创建 DataSourceBuilder 对象,并根据 Spring Boot 的配置文件(application.properties/yml)中的配置,依次设置数据源类型、驱动类名、连接 url、 用户名和密码等信息。
public DataSourceBuilder<?> initializeDataSourceBuilder() {
return DataSourceBuilder.create(this.getClassLoader()).type(this.getType()).
driverClassName(this.determineDriverClassName()).url(this.determineUrl()).username(this.determineUsername()).password(this.determinePassword());
}
上面提到 spring.datasource.type 默认是可以不用配置的,因此在 createDataSource() 方法在获取到回传回来的 DataSourceBuilder 对象后,还需要将其 type 属性再次设置为 HikariDataSource,并调用 DataSourceBuilder 的 build() 方法,完成 HikariDataSource 的初始化。
dataSource()
方法获得数据源对象,并设置了连接池的名字(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 作为其数据源。
Java | Spring Boot数据源配置原理的更多相关文章
- Spring Boot自动配置原理、实战
Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...
- Spring Boot自动配置原理(转)
第3章 Spring Boot自动配置原理 3.1 SpringBoot的核心组件模块 首先,我们来简单统计一下SpringBoot核心工程的源码java文件数量: 我们cd到spring-boot- ...
- 峰哥说技术:06-手撸Spring Boot自定义启动器,解密Spring Boot自动化配置原理
Spring Boot深度课程系列 峰哥说技术—2020庚子年重磅推出.战胜病毒.我们在行动 06 峰哥说技术:手撸Spring Boot自定义启动器,解密Spring Boot自动化配置原理 Sp ...
- Spring Boot自动配置原理与实践(二)
前言 在之前的博文(Spring Boot自动配置原理与实践(一))中,已经介绍了Spring boot的自动配置的相关原理与概念,本篇主要是对自动配置的实践,即自定义Starter,对原理与概念加深 ...
- Springboot 系列(三)Spring Boot 自动配置原理
注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别. 前言 关于配置文件可以配置的内容,在 Spring ...
- Spring Boot自动配置原理与实践(一)
前言 Spring Boot众所周知是为了简化Spring的配置,省去XML的复杂化配置(虽然Spring官方推荐也使用Java配置)采用Java+Annotation方式配置.如下几个问题是我刚开始 ...
- Spring Boot自动配置原理懂后轻松写一个自己的starter
目前很多Spring项目的开发都会直接用到Spring Boot.因为Spring原生开发需要加太多的配置,而使用Spring Boot开发很容易上手,只需遵循Spring Boot开发的约定就行了, ...
- spring boot 自动配置原理
1).spring boot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration,先看一下启动类的main方法 public ConfigurableApplic ...
- Spring Boot 自动配置原理(精髓)
一.自动配置原理(掌握) SpringBoot启动项目会加载主配置类@SpringBootApplication,开启@EnableAutoConfiguration自动配置功能 @EnableAut ...
- Spring Boot自动配置原理
使用Spring Boot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这 是如何做到的? 一切魔力的开始,都是从我们的main函数来的,所以我们再次来 ...
随机推荐
- Intellij IDEA开发Scala程序
前言 Intellij IDEA是一款功能强大的集成开发环境(IDE),可用于开发各种编程语言,包括Scala.Scala是一种功能强大的静态类型编程语言,它结合了面向对象和函数式编程的特性. 本文我 ...
- 逻辑回归(Logistic Regression) ----转载
概要: 1. 介绍Logistic Regression的数学模型,推导并详细解释求解最优回归系数的过程:2. Python实现Logistic Regression的基本版:3. 介绍sklearn ...
- 链表K个节点的组内逆序调整问题
链表K个节点的组内逆序调整问题 作者:Grey 原文地址: 博客园:链表K个节点的组内逆序调整问题 CSDN:链表K个节点的组内逆序调整问题 题目描述 LeetCode 25. Reverse Nod ...
- MySQL-防止误删除的方案就是删除,看不见岂不就是删除了吗,所以就是把它隐藏起来。
版权声明:原创作品,谢绝转载!否则将追究法律责任. ----- 作者:kirin 伪删除: 用update替代delete 1.添加状态列 ALTER TABLE student2 ADD state ...
- 聊聊大数据框架的数据更新策略: COW,MOR,MOW
大数据框架下,常用的数据更新策略有三种: COW: copy-on-write, 写时复制; MOR: merge-on-read, 读时合并; MOW: merge-on-write, 写时合并; ...
- net8获取泛微token以及访问api示例
工作中涉及到调用泛微的场景,官方的示例又臭又长,抽空用NET8简化了写法,为了简化http访问,用了Flurl.Http这个库.在座各位大佬,我们直接就看代码了 using System.Secu ...
- 轻量型 Web SCADA 组态软件 TopLink
图扑物联 发布了一款工业物联网边缘侧应用场景的轻量型 Web SCADA 组态软件 Iotopo TopLink.该产品采用 B/S 架构,提供 Web 管理界面,软件包大小仅 23MB,无需安装客户 ...
- Oracle数据字典(各种视图、表)
数据字典是存放整个数据库实例重要信息的一组表,这些数据字典大部分都是SYS用户所有. 数据字典的构成 Oracle数据字典名称由前缀和后缀组成,使用下画线"_"连接.其代表的含义如 ...
- STM32CubeMX教程1 工程建立
1.准备材料 开发板(STM32F407G-DISC1) ST-LINK/V2驱动 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) 2 ...
- 终于肝完了!全网最全、最详细、最全面的 Hadoop大数据学习教程( 2023最新版 )
大家好,我是民工哥! 前面给大家介绍了:关系型数据库 MySQL . NoSQL 数据库 Redis . MongoDB .搜索引擎 ElasticSearch 等知识体系学习的文章. 在当今这样的就 ...