springboot8--->springboot自动配置数据源DataSource原理分析

1、使用简介

      我们在使用spring boot的时候我们配置一个数据源主要是通过如下配置来进行定义

配置数据源的类型,比如druid,不配置会使用默认的数据源类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

配置数据源的数据库服务地址
spring.datasource.url=jdbc:mysql://localhost:3306/test?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8

配置数据源的驱动类
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

配置数据源数据库服务的用户名称
spring.datasource.username=root

配置数据源数据库服务的用户密码
spring.datasource.password=123456

    就这样配置完成后,在spring ioc容器中就会有一个beanName=dataSource的bean实例。

 

2、自动配置数据源的原理分析

      2.1、还是老规矩来到spring-boot-autoconfigure包下面的spring boot SPI文件spring.factories文件中,我们去查找数据源自动配置的配置类,结果如下:

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\

       2.2、我们重点关注的是DataSourceAutoConfiguration这个配置类,其他的都大同小异,还是老规矩既然DataSourceAutoConfiguration是一个配置类,我们第一关注的就是这个类上面的注解:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {

     第一查看的是@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) 在类路径下要有这两个类才会激活当前配置类,DataSource是javax.sql.DataSource 肯定是已经存在当前类路径下的,EmbeddedDatabaseType这个类的全路径是啥呢??经过查看源码我们发现是org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType类型,那么这个类在什么包里面呢? 我们需要怎样引入依赖呢?

      经过查看源码我们发现EmbeddedDatabaseType这个类存在于spring-jdbc这个jar包里面,那么是不是我们引入spring-jdbc这个jar包后就能激活DataSourceAutoConfiguration这个配置类呢? 答案是肯定的,我们引入spring-jdbc的jar包后,我们配置文件中配置数据的配置如下:我们会发现在springIOC容器中果然配置好了一个datasource实例。

配置数据源的类型,比如druid,不配置会使用默认的数据源类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

配置数据源的数据库服务地址
spring.datasource.url=jdbc:mysql://localhost:3306/test?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8

配置数据源的驱动类
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

配置数据源数据库服务的用户名称
spring.datasource.username=root

配置数据源数据库服务的用户密码
spring.datasource.password=123456

      我们通过引入spring-jdbc的jar包后可以完成我们的数据源DataSource的配置,但是这样引入的话我们还需要关系spring-jdbc的版本问题,不是很方便,因此spring boot提供了一个启动包spring-boot-starter-jdbc,这个jar的pom.xml如下:

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.3.3.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.zaxxer</groupId>
      <artifactId>HikariCP</artifactId>
      <version>3.4.5</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.8.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

   我们可以看出来,spring-boot-starter-jdbc这个启动包引入了spring-jdbc、HikariCP这个两个很重要的包,既然引入了spring-jdbc这个包,那么我们的DataSourceAutoConfiguration这个配置类就被激活了,那么为什么好要引入HikariCP这个包呢?HikariCP这个包是一个数据源,有小日本开发的,据说性能第一,这也是在spring boot中默认使用的数据源。

   引入HikariCP这个包后,是怎样实现默认配置的数据源类型是HikariCP是呢?????

   在DataSourceAutoConfiguration这个类中定义了如下bean定义:

	@Configuration(proxyBeanMethods = false)
	@Conditional(PooledDataSourceCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })

    在这里引入了很多类型数据源的自动配置类
	@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
			DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
			DataSourceJmxConfiguration.class })
	protected static class PooledDataSourceConfiguration {

	}

           我们可以看到会导入4中数据源的配置类,分别如下:

                               1、Hikari       :  提供配置HikariDataSource

                               2、Tomcat     :提供配置org.apache.tomcat.jdbc.pool.DataSource

                               3、Dbcp2      :org.apache.commons.dbcp2.BasicDataSource

                               4、Generic    :如果配置了spring.datasource.type属性就按照配置的数据源类型来配置数据源。比如Druid。

             我们来查看DataSourceConfiguration.Hikari这个配置类,源码如下:

	/**
	 * Hikari DataSource configuration.
	 */
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(HikariDataSource.class)  类路径下必须存在HikariDataSource这个类
	@ConditionalOnMissingBean(DataSource.class)  当前容器中存在DataSource类型的bean

    如果spring.datasource.type配置了,如果配置的值为com.zaxxer.hikari.HikariDataSource
    或者没有配置spring.datasource.type这个值 那就激活HikariDataSource的自动配置类。
	@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
			matchIfMissing = true)
	static class Hikari {

		@Bean
        这个注解表示我们可以指定配置以spring.datasource.hikari为前缀的配置项来配置hikari数据源
           例如:spring.datasource.hikari.jdbc-url=xxx
                 spring.datasource.hikari.driver-class-name=xxx
                 spring.datasource.hikari.username=xxx
                 spring.datasource.hikari.password=xxx
                 ...
		@ConfigurationProperties(prefix = "spring.datasource.hikari")

        那么为什么我们不配置以spring.datasource.hikari为前缀的配置项如spring.datasource.url
等配置也能生效呢?此处的properties就是我们配置的spring.datasource.url等配置项,毫无疑问spring 
boot肯定帮我们做了映射,源码中也确实发现了,有兴趣的可以自行调试。

		HikariDataSource dataSource(DataSourceProperties properties) {
			HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
			if (StringUtils.hasText(properties.getName())) {
				dataSource.setPoolName(properties.getName());
			}
			return dataSource;
		}

	}

      

        接着我们来看看DataSourceConfiguration.Dbcp2配置类的实现,源码如下:

	/**
	 * DBCP DataSource configuration.
	 */
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
	@ConditionalOnMissingBean(DataSource.class)

    这里也是如果没有配置spring.datasource.type或者
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource的时候激活了,那么问题来了,如
果我同时激活Hikari、Dbcp2且不配置spring.datasource.type,那么最后究竟会选择哪一个呢?????

	@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource",
			matchIfMissing = true)
	static class Dbcp2 {

		@Bean
		@ConfigurationProperties(prefix = "spring.datasource.dbcp2")
		org.apache.commons.dbcp2.BasicDataSource dataSource(DataSourceProperties properties) {
			return createDataSource(properties, org.apache.commons.dbcp2.BasicDataSource.class);
		}

	}

     上面抛出了问题,如果激活了两种数据源你的配置类,会以那种数据源的配置类配置数据源,经过测试还是会选择Hikari。

 

  最后我们来说一下DataSourceConfiguration.Generic , 源码如下:

	/**
	 * Generic DataSource configuration.
	 */
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingBean(DataSource.class)

    如果配置了spring.datasource.type属性就激活,如果配置的spring.datasource.type不是其他数据源
类型的,就会使用次数据源配置类,会根据配置的数据源类型来进行数据源配置,比如配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 是阿里的druid,那么最后配置的数
据源就是DruidDataSource。
	@ConditionalOnProperty(name = "spring.datasource.type")
	static class Generic {

		@Bean
		DataSource dataSource(DataSourceProperties properties) {
			return properties.initializeDataSourceBuilder().build();
		}

	}

整个数据源的配置原理就是这样。

 

3、同理redis的连接工厂配置原理也是一样的方式,大同小异。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值