SpringBoot-11-JDBC原理解析

SpringBoot-11-JDBC


SpringData简介

对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。

Spring Data 官网
查看数据库相关的启动器 :官方文档

整合JDBC

1.创建一个新项目:springboot-04-jdbc,引入相应的模块

在这里插入图片描述
2.项目搭建好后,查看spring Boot给我们导入的场景启动器和依赖

在这里插入图片描述
3.在全局(appication.yaml)配置文件编写数据源


#数据源连接信息
spring:
    datasource:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/test?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
      username: root
      password: root
  1. 测试


@SpringBootTest
class Springboot04JdbcApplicationTests {

    //自动装配数据源
    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        //查看数据源
        System.out.println(dataSource.getClass());
        //获得连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        //关闭连接
        connection.close();

    }

}

运行结果
在这里插入图片描述
Spring Boot 默认使用 HikariCP 作为其数据源,对数据库的访问。

可以通过修改配置文件来修改数据源

实现如下:

spring:
    datasource:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/test?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
      username: root
      password: root
      # 修改默认数据源
      type: org.springframework.jdbc.datasource.DriverManagerDataSource

运行结果

在这里插入图片描述

Spring Boot版本2.2.5默认使用HikariDataSource作为数据源,而以前版本 如Spring Boot版本1.5默认使用 org.apache.tomcat.jdbc.pool.DataSource 作为数据源。

HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀;

可以spring.datasource.type 指定自定义的数据源类型,值为 要使用的连接池实现的完全限定名。

分析原理

SpringBoot 几乎所有的默认配置都是通过配置类XxxAutoConfiguration进行配置,Spring Boot 的数据源也不例外,它的自动配置类是DataSourceAutoConfiguration

在/META-INF/spring.factories文件找到DataSourceAutoConfiguration配置类

在这里插入图片描述
EmbeddedDataSourceConfiguration 向容器中添加了一个 Spring Boot 内嵌的数据源,该数据源支持 HSQL,H2 和 DERBY 三种数据库

在这里插入图片描述

DataSourceAutoConfiguration共包括5个内部配置类

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

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

EmbeddedDatabaseConfiguration


	@Configuration(proxyBeanMethods = false)
	@Conditional(EmbeddedDatabaseCondition.class)
	//容器汇总没有数据源的配置类下生效
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@Import(EmbeddedDataSourceConfiguration.class)
	protected static class EmbeddedDatabaseConfiguration {

	}

EmbeddedDatabaseConfiguration是内嵌的数据源配置类,类中没有任何方法实现,主要的功能是通过@Import注解引入EmbeddedDataSourceConfiguration类实现的

	@Import(EmbeddedDataSourceConfiguration.class)

点击EmbeddedDataSourceConfiguration



@Configuration(proxyBeanMethods = false)
//开启配置属性,绑定DataSourceProperties类
@EnableConfigurationProperties(DataSourceProperties.class)
public class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware {

	private ClassLoader classLoader;

	@Override
	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),但这是有条件限制的。

条件限制:

	@Conditional(EmbeddedDatabaseCondition.class)
	protected static class EmbeddedDatabaseConfiguration {

	}

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

说明:

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

		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
			ConditionMessage.Builder message = ConditionMessage.forCondition("EmbeddedDataSource");
			if (hasDataSourceUrlProperty(context)) {
				return ConditionOutcome.noMatch(message.because(DATASOURCE_URL_PROPERTY + " is set"));
			}
			if (anyMatches(context, metadata, this.pooledCondition)) {
				return ConditionOutcome.noMatch(message.foundExactly("supported pooled data source"));
			}
			EmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(context.getClassLoader()).getType();
			if (type == null) {
				return ConditionOutcome.noMatch(message.didNotFind("embedded database").atAll());
			}
			return ConditionOutcome.match(message.found("embedded database").items(type));
		}

PooledDataSourceConfiguration



	@Configuration(proxyBeanMethods = false)
	@Conditional(PooledDataSourceCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
			DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
			DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
	protected static class PooledDataSourceConfiguration {

	}

  • PooledDataSourceConfiguration 是池化数据源的自动配置类,通过@Conditional注解可知,该注解使用DataSourceAutoConfiguration的内部限制条件类PooledDataSourceCondition来进行条件判断。

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

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

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

在这里插入图片描述

以 Hikari 为例进行分析


	@Configuration(proxyBeanMethods = false)
	//表示这是一个配置类
	@ConditionalOnClass(HikariDataSource.class)
	//表示必须类路径下存在HikariDataSource类,这个配置类才会被实例化
	//HikariDataSource 类是由 spring- boot-starter-jdbc 默认将其引入的,因此只要我们在 pom.xml 中引入了该 starter, Hikari 就会被实例化
	@ConditionalOnMissingBean(DataSource.class)
	//容器中没有DataSource这个类,才会被实例化
	@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
			matchIfMissing = true)
	//Spring Boot配置文件时,配置了spring.datasource.type=com.zaxxer.hikari.HikariDataSource或者不配置spring.datasource.tyoe时,Hikari才会被实例化
	static class Hikari {

		@Bean
		// 与配置文件名为spring.datasource.hikari下的所有属性绑定
		@ConfigurationProperties(prefix = "spring.datasource.hikari")
		HikariDataSource dataSource(DataSourceProperties properties) {
			HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
			if (StringUtils.hasText(properties.getName())) {
				dataSource.setPoolName(properties.getName());
			}
			return dataSource;
		}

	}

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

createDataSource()

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

DataSourceProperties类

在这里插入图片描述
可以知道,DataSourceProperties和我们之前在全局配置下的spring.datasource的所有属性一一对应绑定在一起,DataSourceProperties里面包含数据库的连接数据库和释放数据库等操作/.

调用了DataSourceProperties的initializeDataSourceBuilder()初始化DataSourceBuilder

initializeDataSourceBuilder()

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

initialDataSourceBuilder()方法通过调用DataSourceBulider的create()方法,将application.properties/yaml的配置,依次设置数据源类型、驱动类名、连接 url、 用户名和密码等信息。

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

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

dataSource() 方法获得数据源对象,并设置了连接池的名字(name),注入到容器中。
在这里插入图片描述

总结:

  • 用户没有配置数据源的情况,若容器中存在 HikariDataSource 类,则 Spring Boot 就会自动实例化 Hikari,并将其作为其数据源。
  • Spring Boot 的 JDBC 场景启动器(spring-boot-starter-data-jdbc)通过 spring- boot-starter-jdbc 默认引入了 HikariCP 数据源(包含 HikariDataSource 类),因此 Spring Boot 默认使用 HikariCP 作为其数据源。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值