装载至:https://www.cnblogs.com/storml/p/8611388.html

Spring Boot实现了自动加载DataSource及相关配置。当然,使用时加上@EnableAutoConfiguration注解是必须的。下面就是对这一部分的源码分析。

(1)Spring Boot启动后会调用org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration。下面是部分源码。

 1 @Configuration
2 @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
3 @EnableConfigurationProperties(DataSourceProperties.class)
4 @Import({ DataSourcePoolMetadataProvidersConfiguration.class,
5 DataSourceInitializationConfiguration.class })
6 public class DataSourceAutoConfiguration {
7
8 @Configuration
9 @Conditional(EmbeddedDatabaseCondition.class)
10 @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
11 @Import(EmbeddedDataSourceConfiguration.class)
12 protected static class EmbeddedDatabaseConfiguration {
13 }
14
15 @Configuration
16 @Conditional(PooledDataSourceCondition.class)
17 @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
18 @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
19 DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
20 DataSourceJmxConfiguration.class })
21 protected static class PooledDataSourceConfiguration {
22 }
23 ......
24 }

我们从中可以看出,DataSourceAutoConfiguration中有两个嵌套类,一个是EmbeddedDatabaseConfiguration,另一个是PooledDataSourceConfiguration

EmbeddedDatabaseConfiguration表示已经嵌入Spring Boot的DataSource,除了Maven中加入相应的Driver,可以不做其他额外配置就能使用。从EmbeddedDatabaseType类可以看出,Spring Boot的内嵌DataSource支持HSQL,H2,DERBY这三种DB。

PooledDataSourceConfiguration表示Spring Boot还支持一些实现Pool的DataSource。从org.springframework.boot.jdbc.DataSourceBuilder中可以看出,当前版本的Spring Boot(2.0)只支持com.zaxxer.hikari.HikariDataSource,org.apache.tomcat.jdbc.pool.DataSource,org.apache.commons.dbcp2.BasicDataSource。其中,性能更加优秀的HikariDataSource是Spring Boot的默认选择(DataSourceBuilderDATA_SOURCE_TYPE_NAMES[0] = com.zaxxer.hikari.HikariDataSource)。所以,当application.yml文件中做如下配置时,Spring Boot默认使用HikariDataSource数据库连接池。

spring:
datasource:
url: jdbc:mysql://localhost:3306/sas
username: root
password: ****
driver-class-name: com.mysql.jdbc.Driver
#type: com.zaxxer.hikari.HikariDataSource

(2)我们以HikariDataSource举例,接下来调用PooledDataSourceConfigurationorg.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration抽象类的Hikari嵌套类(DataSourceConfiguration抽象类的一个实现类)。

 1 abstract class DataSourceConfiguration {
2
3 @SuppressWarnings("unchecked")
4 protected <T> T createDataSource(DataSourceProperties properties,
5 Class<? extends DataSource> type) {
6 return (T) properties.initializeDataSourceBuilder().type(type).build();
7 }
8
9 /* Omit Tomcat Pool DataSource configuration.*/
10 /**
11 * Hikari DataSource configuration.
12 */
13 @ConditionalOnClass(HikariDataSource.class)
14 @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
15 static class Hikari extends DataSourceConfiguration {
16
17 @Bean
18 @ConfigurationProperties(prefix = "spring.datasource.hikari")
19 public HikariDataSource dataSource(DataSourceProperties properties) {
20 HikariDataSource dataSource = createDataSource(properties,
21 HikariDataSource.class);
22 if (StringUtils.hasText(properties.getName())) {
23 dataSource.setPoolName(properties.getName());
24 }
25 return dataSource;
26 }
27 }
28 /* Omit DBCP DataSource configuration.*/
29 }

我们从黄色部分可以看出,当application.yml文件中配置spring.datasource.type = com.zaxxer.hikari.HikariDataSource时,会使用HikariDataSource作为数据库连接池(当然上面也分析了,它是默认选择)。我们从绿色部分可以看出它的配置信息主要从两个类中读取,一个是org.springframework.boot.autoconfigure.jdbc.DataSourceProperties,另一个则是本类HikariDataSource的父类com.zaxxer.hikari.HikariConfig

@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {}
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {}

我们从@ConfigurationProperties配置及两个具体的类所包含的的域可以得出配置HikariDataSource信息。下面是例子。

spring:
datasource:
name: #Name of the datasource. Default to "testdb" when using an embedded database.
driverClassName: #Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
url: #DBC URL of the database.
type: #Fully qualified name of the connection pool implementation to use. By default, it is auto-detected from the classpath.
username: #Login username of the database.
password: #Login password of the database.
## For more details please see DataSourceProperties.
hikari:
connectionTimeout:
validationTimeout:
maxPoolSize:
minIdle:
dataSourceProperties:
## For more details please see HikariConfig.

(3)当读完配置后,则会通过HikariDataSource.getConnection()方法创建HikariPool对象。HikariPool及其父类PoolBase做了许多复杂的工作,包括创建Pool,创建Connection,读取Config,验证等等。调用HikariDataSource.getConnection()方法最终得到了这个Connection对象。这个过程中主要做了以下几步:

① 创建HikariPool对象。

② 调用HikariPool对象的父类对象PoolBase的构造器,读取HikariConfig配置信息配置PoolBase的属性。

③ 调用PoolBase的构造器的initializeDataSource方法,利用com.zaxxer.hikari.util.DriverDataSource创建DataSource对象(这里主要指JDBC URL方式)。DriverDataSource中会把所有的DataSource信息封装到driverProperties属性中,这是为了适配java.sql.Driverconnect(String url, java.util.Properties info)方法。

 1 public final class DriverDataSource implements DataSource {
2
3 private final String jdbcUrl;
4 private final Properties driverProperties;
5 private Driver driver;
6
7 public DriverDataSource(String jdbcUrl, String driverClassName, Properties properties, String username, String password) {
8 this.jdbcUrl = jdbcUrl;
9 this.driverProperties = new Properties();
10 Iterator e = properties.entrySet().iterator();
11
12 while(e.hasNext()) {
13 Entry driverClass = (Entry)e.next();
14 this.driverProperties.setProperty(driverClass.getKey().toString(), driverClass.getValue().toString());
15 }
16
17 if(username != null) {
18 this.driverProperties.put("user", this.driverProperties.getProperty("user", username));
19 }
20
21 if(password != null) {
22 this.driverProperties.put("password", this.driverProperties.getProperty("password", password));
23 }
24 ......
25 }
26
27 @Override
28 public Connection getConnection() throws SQLException
29 {
30 return driver.connect(jdbcUrl, driverProperties);
31 }
32 }

④ 调用HikariPool对象的构造器,同样也是配置一堆线程池信息。

⑤ 返回HikariPool.getConnection()。这个过程中,做了包含PoolBase.newPoolEntry()PoolBase.newConnection()的许多复杂方法。从PoolBase.newConnection()可以看出,最终还是调用的步骤③的getConnection()方法获取到了这个Connection对象。

 1    private Connection newConnection() throws Exception
2 {
3 final long start = currentTime();
4
5 Connection connection = null;
6 try {
7 String username = config.getUsername();
8 String password = config.getPassword();
9
10 connection = (username == null) ? dataSource.getConnection() : dataSource.getConnection(username, password);
11 if (connection == null) {
12 throw new SQLTransientConnectionException("DataSource returned null unexpectedly");
13 }
14
15 setupConnection(connection);
16 lastConnectionFailure.set(null);
17 return connection;
18 }
19 catch (Exception e) {
20 if (connection != null) {
21 quietlyCloseConnection(connection, "(Failed to create/setup connection)");
22 }
23 else if (getLastConnectionFailure() == null) {
24 LOGGER.debug("{} - Failed to create/setup connection: {}", poolName, e.getMessage());
25 }
26
27 lastConnectionFailure.set(e);
28 throw e;
29 }
30 finally {
31 // tracker will be null during failFast check
32 if (metricsTracker != null) {
33 metricsTracker.recordConnectionCreated(elapsedMillis(start));
34 }
35 }
36 }

Spring Boot JDBC:加载DataSource过程的源码分析及yml中DataSource的配置的更多相关文章

  1. Spring Boot启动命令参数详解及源码分析

    使用过Spring Boot,我们都知道通过java -jar可以快速启动Spring Boot项目.同时,也可以通过在执行jar -jar时传递参数来进行配置.本文带大家系统的了解一下Spring ...

  2. SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)

    Spring Boot默认使用Tomcat作为嵌入式的Servlet容器,只要引入了spring-boot-start-web依赖,则默认是用Tomcat作为Servlet容器: <depend ...

  3. (转)spring boot实战(第六篇)加载application资源文件源码分析

    原文:http://blog.csdn.net/liaokailin/article/details/48878447

  4. spring boot启动加载项CommandLineRunner

    spring boot启动加载项CommandLineRunner 在使用SpringBoot构建项目时,我们通常有一些预先数据的加载.那么SpringBoot提供了一个简单的方式来实现–Comman ...

  5. Android 图片加载框架Glide4.0源码完全解析(二)

    写在之前 上一篇博文写的是Android 图片加载框架Glide4.0源码完全解析(一),主要分析了Glide4.0源码中的with方法和load方法,原本打算是一起发布的,但是由于into方法复杂性 ...

  6. Android必学-异步加载+Android自定义View源码【申明:来源于网络】

    Android必学-异步加载+Android自定义View源码[申明:来源于网络] 异步加载地址:http://download.csdn.net/detail/u013792369/8867609 ...

  7. ArcGIS紧凑型切片读取与应用2-webgis动态加载紧凑型切片(附源码)

    1.前言 上篇主要讲了一下紧凑型切片的的解析逻辑,这一篇主要讲一下使用openlayers动态加载紧凑型切片的web地图服务. 2.代码实现 上篇已经可以通过切片的x.y.z得对应的切片图片,现在使用 ...

  8. Spring PropertyResolver 占位符解析(二)源码分析

    Spring PropertyResolver 占位符解析(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) ...

  9. 《Linux内核设计的艺术》学习笔记(一)从开机加电到加载三个汇编源码

      实验内核版本:0.11 ◆ 从开机到main函数的三步: ① 启动BIOS,准备实模式下的中断向量表和中断服务程序: ② 从启动盘加载OS程序到内存中,加载OS程序的工作就是利用第一步中的中断服务 ...

随机推荐

  1. javascript学习3、数据类型、数据类型转换、运算符

    数据类型包括:基本数据类型和引用数据类型 基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构成的对象. 当我们把变量赋值给一个变量时,解析器首先要确认的就是这个值是基本类型值还是引用类型值 ...

  2. 项目中有私有仓库模块时,使用 npm ci 命令的安装步骤

    项目中有私有仓库模块时,使用 npm ci 命令的安装步骤: 先安装私有仓库模块:npm install <npm包名> --registry=<npm包源> 再运行命令:np ...

  3. oracle中删除表:drop、delete、truncate

    相同点,使用drop delete truncate 都会删除表中的内容 drop table 表名 delete from 表名(后面不跟where语句,则删除表中所有的数据) truncate t ...

  4. MySQL 练习题目 二刷 - 2019-11-4 5:55 am

    建表的过程 create table student( sid int not null primary key, sname ) not null, sborn date, ssex ) not n ...

  5. random库

    伪随机数的原因: random库中函数主要用于产生各种分布的伪随机数序列.random库中的随机函数是按照一定算法模拟产生的,其概率是确定的.可见的,所以被称为伪随机数.而真正意义上的随机数是按照实验 ...

  6. podium服务器端的微前端开发框架

    podium 是一个比较全的微前端开发框架. 具有以下特性 自治开发 强大的组合能力 基于约定的开发模式 podium 包含的组件 podlets 页面片段,是一个独立的http 服务,独立运行的,实 ...

  7. centos 部署的时候安装不上Mariadb,缺少依赖文件

    并不存在这个sock文件 使用systemctl status mariadb.service 查看报错信息 提示libsystemd.so.0文件不存在, 安装systemd-libs包,解决问题, ...

  8. type of的返回值有哪些

    typeof 10; // number typeof 'time'; //string typeof undefined; // undefined typeof null; // object t ...

  9. P3350 [ZJOI2016]旅行者

    题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...

  10. JS回调函数怎么写的?

    相信每个做前端的同学都用过太多太多的回调函数, 接下来就看看回调函数是怎么来的. 这玩意儿也没那么神秘,直接看代码: 声明函数的时候,把回调函数用作参数,并且在函数内调用它 function getD ...