Springboot2.5.x版本之自动创建(H2/DERBY/HSQL)数据源源码分析-yellowcong

news2024/11/25 5:50:38

场景:当我们没有配置mysql,postgresql等数据源的时候,pom.xml里面引入了H2/DERBY/HSQL jar包,也没有配置连接,却有数据源创建的情况。
springboot启动的第一步
1.DataSourceAutoConfiguration 配置类启动
2.DataSourceProperties 配置类自动探测datasource的配置项
3.EmbeddedDatabaseConnection 做检测,自动生成数据库连接
4.DataSourceProperties.initializeDataSourceBuilder 创建数据源连接
5.DataSourceConfiguration 根据不同的数据源来创建连接池

1. 数据源配置启动类

找到 spring-boot-autoconfigure-2.5.x.jar 这个jar包,里面的META-INF/spring.factories 文件,有各个自动化配置的入口,数据库入口查找org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration 这个类
在这里插入图片描述

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
...
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
...

2. DataSourceAutoConfiguration类核心代码

数据库自动数据库连接池配置的前提是,项目中没有别的模块创建了DataSource ( @ConditionalOnMissingBean({DataSource.class, XADataSource.class}) 这句代码就是做限制的)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.boot.autoconfigure.jdbc;


@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(
    type = {"io.r2dbc.spi.ConnectionFactory"}
)
//导入DataSourceProperties 的配置 ,实际数据库参数都是在这个类做的
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({DataSourcePoolMetadataProvidersConfiguration.class, InitializationSpecificCredentialsDataSourceInitializationConfiguration.class, SharedCredentialsDataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {
    public DataSourceAutoConfiguration() {
    }

    //.... 省略代码

   //当没有手动创建DataSource的情况,就会走默认的数据源连接池
   //目前支持的数据源连接池
   //Hikari,Tomcat,Dbcp2,OracleUcp,Generic,DataSourceJmxConfiguration 
    @Configuration(
        proxyBeanMethods = false
    )
    @Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class})
    @ConditionalOnMissingBean({DataSource.class, XADataSource.class})
    @Import({Hikari.class, Tomcat.class, Dbcp2.class, OracleUcp.class, Generic.class, DataSourceJmxConfiguration.class})
    protected static class PooledDataSourceConfiguration {
        protected PooledDataSourceConfiguration() {
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @Conditional({DataSourceAutoConfiguration.EmbeddedDatabaseCondition.class})
    @ConditionalOnMissingBean({DataSource.class, XADataSource.class})
    @Import({EmbeddedDataSourceConfiguration.class})
    protected static class EmbeddedDatabaseConfiguration {
        protected EmbeddedDatabaseConfiguration() {
        }
    }
    //.... 省略代码
}

3. DataSourceProperties 数据源配置

注入配置的数据库连接池配置项,然后设定对应的EmbeddedDatabaseConnection ,其中initializeDataSourceBuilder的调用方是DataSourceConfiguration.createDataSource ,在最后创建数据库连接池的时候调用。

数据库探测规则:1.优先使用用户配置的(spring.datasource.url)url选项,2.如果有户没有配置,就会使用EmbeddedDatabaseConnection 来探测,默认会扫描jar(H2/DERBY/HSQL)包,取第一个为默认值。

@ConfigurationProperties(
    prefix = "spring.datasource"
)
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
    //.... 省略代码
    //设置 EmbeddedDatabaseConnection的检查类
    public void afterPropertiesSet() throws Exception {
        if (this.embeddedDatabaseConnection == null) {
            this.embeddedDatabaseConnection = EmbeddedDatabaseConnection.get(this.classLoader);
        }

    }

    // 创建连接池,调用了this.determineDriverClassName 探测数据库连接地址
    public DataSourceBuilder<?> initializeDataSourceBuilder() {
        return DataSourceBuilder.create(this.getClassLoader()).type(this.getType()).driverClassName(this.determineDriverClassName()).url(this.determineUrl()).username(this.determineUsername()).password(this.determinePassword());
    }

	//探测连接地址,默认会根据url进行分析探测,如果没有的情况,就会走EmbeddedDatabaseConnection 来获取内置数据库
    public String determineDriverClassName() {
        if (StringUtils.hasText(this.driverClassName)) {
            Assert.state(this.driverClassIsLoadable(), () -> {
                return "Cannot load driver class: " + this.driverClassName;
            });
            return this.driverClassName;
        } else {
            String driverClassName = null;
            if (StringUtils.hasText(this.url)) {
                driverClassName = DatabaseDriver.fromJdbcUrl(this.url).getDriverClassName();
            }

            if (!StringUtils.hasText(driverClassName)) {
                driverClassName = this.embeddedDatabaseConnection.getDriverClassName();
            }

            if (!StringUtils.hasText(driverClassName)) {
                throw new DataSourceProperties.DataSourceBeanCreationException("Failed to determine a suitable driver class", this, this.embeddedDatabaseConnection);
            } else {
                return driverClassName;
            }
        }
    }
    //.... 省略代码
}

4. EmbeddedDatabaseConnection 内置数据库探测

通过EmbeddedDatabaseConnection ,来探测数据库信息,会根据大家有没有(h2/derby/hsql)这些jar包,来确认是。

public enum EmbeddedDatabaseConnection {
    NONE((EmbeddedDatabaseType)null, (String)null, (String)null, (url) -> {
        return false;
    }),
    H2(EmbeddedDatabaseType.H2, DatabaseDriver.H2.getDriverClassName(), "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE", (url) -> {
        return url.contains(":h2:mem");
    }),
    DERBY(EmbeddedDatabaseType.DERBY, DatabaseDriver.DERBY.getDriverClassName(), "jdbc:derby:memory:%s;create=true", (url) -> {
        return true;
    }),
    /** @deprecated */
    @Deprecated
    HSQL(EmbeddedDatabaseType.HSQL, DatabaseDriver.HSQLDB.getDriverClassName(), "org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:%s", (url) -> {
        return url.contains(":hsqldb:mem:");
    }),
    HSQLDB(EmbeddedDatabaseType.HSQL, DatabaseDriver.HSQLDB.getDriverClassName(), "org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:%s", (url) -> {
        return url.contains(":hsqldb:mem:");
    });
	
	//查找H2, HSQLDB, DERBY 中的driverClass 第一个
    private static EmbeddedDatabaseConnection getEmbeddedDatabaseConnection(String driverClass) {
        return (EmbeddedDatabaseConnection)Stream.of(H2, HSQLDB, DERBY).filter((connection) -> {
            return connection.isDriverCompatible(driverClass);
        }).findFirst().orElse(NONE);
    }
    //.... 省略代码
 }   

5. DataSourceConfiguration 数据库连接池配置类

里面包含了多种数据库连接池Hikari,Tomcat,Dbcp2,OracleUcp,Generic,DataSourceJmxConfiguration ,以Hikari举例 说明。

上面DataSourceAutoConfiguration 类中的PooledDataSourceConfiguration 配置内部类,有个注解@Import({Hikari.class, Tomcat.class, Dbcp2.class, OracleUcp.class, Generic.class, DataSourceJmxConfiguration.class}) , 就会使用DataSourceConfiguration 中的数据库连接池配置信息。

abstract class DataSourceConfiguration {
    //.... 省略代码
    //创建数据库连接池的核心方法
    protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
        return properties.initializeDataSourceBuilder().type(type).build();
    }
    
    @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;
        }
    }
    //.... 省略代码    
}

附录

数据库测试连接配置

---
spring:
  profiles:
    active: db-h2
  #应用唯一标识
  application:
    name: BITSFLOW-CONSOLE
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      maximum-pool-size: 20
      connection-timeout: 300000
      max-life-time: 1800000
      idle-timeout: 0
      pool-name: "CONN-POOL"

---      
spring:
  h2:
    console:
      enabled: true
      path: /h2-console
      settings:
        trace: false
        web-allow-others: true
  config:
    activate:
      on-profile: db-h2
  datasource:
    url: jdbc:h2:mem:yc_test;MODE=MySql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1
    username: sa
    password:
    driver-class-name: org.h2.Driver
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
---
spring:
  config:
    activate:
      on-profile: db-postgresql
  datasource:
    url: jdbc:postgresql://127.0.0.1:5432/yc_test
    username: postgres
    password: demo
    driver-class-name: org.postgresql.Driver
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect

---
spring:
  config:
    activate:
      on-profile: db-mysql
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/yc_test?useUnicode=true&characterEncoding=utf-8&useSSL=false&CreateDatabaseIfNotExists=true&allowMultiQueries=true
    username: root
    password: 'root'
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/571381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DolphinScheduler远程启动任务

我本地有JAVA程序&#xff0c;需要调用DolphinScheduler的接口启动任务&#xff0c;动态去调用 1、DolphinScheduler的内容逻辑关系 先明确DolphinScheduler内部任务的逻辑关系 项目 |——工作流 |——任务&#xff08;节点&#xff09; 我起的是工作流&#xff0c;一个任务完…

Transformer仅有自注意力还不够?微软联合巴斯大学提出频域混合注意力SpectFormer

本文介绍一篇来自英国巴斯大学&#xff08;University of Bath&#xff09;与微软合作完成的工作&#xff0c;研究者从频率域角度入手探究视觉Transformer结构中的频域注意力和多头注意力在视觉任务中各自扮演的作用。 论文链接&#xff1a; https://arxiv.org/abs/2304.06446 …

为什么都说测试岗是巨坑,趁早跳出去?10年测试人告诉你千万别上当了...

每次都有人问我软件测试的前景是什么样的&#xff0c;每年也会有人很多人纷纷涌入测试的岗位上&#xff0c;希望自己能够进入阿里、华为等大厂。 但是测试岗位真的那么吃香吗&#xff1f;今天我结合从零基础小白到测试开发的成长经历&#xff0c;来说下这个行业的发展前景&…

vmware安装debian 11.7.0 配置LVM

vmware安装debian 11.7.0 配置LVM 1、下载镜像2、创建并安装debian 11虚拟机2.1、选择 Graphical install2.2、选择安装过程显示语言和系统语言2.3、选择地区2.4、键盘映射2.5、设置主机名-debian2.6、设置网络-直接跳过2.7、设置root密码2.8、创建普通账户2.9、为普通账户设置…

【论文阅读】Modeling of Bitcoin’s Blockchain Delivery Network

文章目录 摘要一、引言二、相关工作A. BTC 网络的测量报告B. 业务概况对 BTC 网络的影响C. 数据分布算法 三、节点连接性、RTT 和块大小A. 建模节点连接B. 建模往返时间 (RTT)C. 建模区块和交易传输时间 四、数据分发和传播五、交易费率和块费率六、分布式网络的排队模型A. 区块…

C++ 中 switch 的性能优化

问题 有这样一段代码&#xff0c;编译器会傻傻地做多次 compare 来找到对应分支吗&#xff1f; #include <stdio.h> #include <stdlib.h> int func(int i) {return (long)(&i) i rand(); }int test(int flag) {int i 0;switch (flag) {case 0:i func(i);…

软件设计师 试题六零基础做题方法分解

接口要实现implements&#xff0c;父类要继承extends 做题技巧&#xff1a;如果在接口下的代码可以不写public 接口后面有个代码&#xff0c;在下面代码中一定有implements对他实现&#xff0c;接口下面是抽象方法也就是函数的实现&#xff0c;具体的实现再类中&#xff0c; 就…

Spring的Bean的生命周期

Spring的Bean的生命周期 Spring的Bean的生命周期 Spring的Bean的生命周期 Spring的Bean的生命周期包括以下阶段&#xff1a; &#xff08;1&#xff09;实例化Instantiation&#xff08;2&#xff09;填充属性Populate properties&#xff08;3&#xff09;处理Aware接口的回调…

华为OD机试真题 Java 实现【查找充电设备组合】【2023Q1 100分】

一、题目描述 某个充电站&#xff0c;可提供n个充电设备&#xff0c;每个充电设备均有对应的输出功率。任意个充电设备组合的输出功率总和&#xff0c;均构成功率集合P的1个元素。功率集合P的最优元素&#xff0c;表示最接近充电站最大输出功率p_max的元素。 二、输入描述 输…

( 链表) 203. 移除链表元素 ——【Leetcode每日一题】

❓203. 移除链表元素 难度&#xff1a;简单 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1…

探秘 | 如何分辨内网和外网?

目录 &#x1f4a1; 什么是外网IP、内网IP&#xff1f; &#x1f4a1; 对于自有路由器上网的用户&#xff0c;可以这样理解外网IP、内网IP &#x1f4a1; 几个大家经常会问的问题 什么是外网IP、内网IP&#xff1f;很多用户都有一个疑惑&#xff0c;如果不使用路由器拨号上网…

一则历史:为什么网络路径前加一个盘符还能正常工作

有一个比较知名的奇异特性&#xff1a;文件系统在解析 UNC(Universal Naming Convention) 路径时&#xff0c;会故意忽略掉最前面添加的盘符字母。 举个例子&#xff0c;假设服务器上有一个共享文件夹&#xff0c;其路径为&#xff1a;\\server\share\directory&#xff0c;如果…

【网络】HTTP

在上面的文章中&#xff0c;我们学习了网络的基础&#xff0c;和网络中一个伟大的标准 OSI 7层模型。通过上篇文章&#xff0c;我们可以知道网络模型最上层为应用层&#xff0c;那么这篇文章就让我们来一起看一下&#xff0c;我们开发过程中绕不开的一个非常著名的应用层协议&a…

FANUC机器人CC-Link总线通信相关配置的具体方法和步骤详解

FANUC机器人CC-Link总线通信相关配置的具体方法和步骤详解 1. 基本说明 2. 采用CC-Link通信的前提条件 机器人需要安装软件:CC-link Interface(Slave) A05B-*-J786 机器人需要安装硬件通信板卡:CC-Link Remote Device Station PCB A05B- * -J110 通信板卡的安装步骤:

第八章 模块

内容框架 8.1 模块介绍 引入模块 import 模块名 通过一句话&#xff0c;计算机就在指定的位置找到了模块文件&#xff0c;并准备好该文件拥有之后会用到的函数和属性。 引入模块本质上就是在一个python文件中引入另一个python文件 引入模块在文档中还可以设置别名&#xff1a;…

没有权限merge到源git仓库?一招教你如何解决。

在git上贡献项目的时候&#xff0c;一般步骤是&#xff0c;clone源项目到本地&#xff0c;切出一个新的分支&#xff0c;然后在新分支上开发&#xff0c;最后push到远程&#xff0c;然后提出mr。但是对于一些非开源的项目&#xff0c;可能会出现&#xff1a; 这就是说明没有权…

mp4是什么格式?如何录制mp4格式的视频?

案例&#xff1a;怎样录制mp4格式的视频&#xff1f; 【我发现网上大部分视频都是mp4格式&#xff0c;我也想在电脑上录制mp4格式的视频。有没有小伙伴知道录制的方法&#xff1f;】 日常生活中&#xff0c;mp4格式已经成为了我们最常用的视频格式之一。它具有高质量、高压缩…

chatgpt赋能python:Python主进程:一步步了解Python中最重要的进程

Python主进程: 一步步了解Python中最重要的进程 在Python编程中&#xff0c;进程是非常重要的一个概念。Python主进程是Python程序在启动的时候默认创建的一个进程&#xff0c;它是整个程序的核心。在使用Python进行开发的时候&#xff0c;了解Python主进程的概念和功能是非常…

gitlab搭建与认证登录

gitlab搭建与认证登录 gitlab的安装配置gitlab中Ldap认证配置 gitlab的安装配置 参考链接&#xff1a; Gitlab 仓库搭建&#xff08;详细版&#xff09; 以下4项注意点&#xff1a; gitlab安装包&#xff0c;直接访问在浏览器上下载速度很慢&#xff0c;可复制链接到迅雷中进…

淘宝店铺所有商品数据接口

淘宝店铺所有商品数据接口是淘宝提供的一种可以获取某个淘宝店铺所有商品信息的接口。通过该接口&#xff0c;可以获取到该店铺的所有商品信息&#xff0c;包括商品的标题、价格、销量、评分等。接口返回的数据格式为JSON格式&#xff0c;可以方便地处理数据。 我们可以通过调…