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的连接工厂配置原理也是一样的方式,大同小异。

 

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用SpringBoot和Mybatis-plus配置数据源的步骤: 1. 首先,在pom.xml文件中添加Mybatis-plus和数据库驱动的依赖: ```xml <dependencies> <!-- Mybatis-plus依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>最新版本</version> </dependency> <!-- 数据库驱动依赖 --> <dependency> <groupId>数据库驱动的groupId</groupId> <artifactId>数据库驱动的artifactId</artifactId> <version>数据库驱动的版本</version> </dependency> </dependencies> ``` 2. 在application.yml或application.properties文件中配置数据源信息: ```yaml spring: datasource: # 主数据源配置 url: 主数据源的URL username: 主数据源的用户名 password: 主数据源的密码 driver-class-name: 主数据源的驱动类名 # 其他数据源配置 datasources: 数据源1的名称: url: 数据源1的URL username: 数据源1的用户名 password: 数据源1的密码 driver-class-name: 数据源1的驱动类名 数据源2的名称: url: 数据源2的URL username: 数据源2的用户名 password: 数据源2的密码 driver-class-name: 数据源2的驱动类名 ``` 3. 创建多数据源配置类,继承AbstractRoutingDataSource,并重写determineCurrentLookupKey方法,根据注解选择使用哪个数据源: ```java @Configuration public class MultipleDataSourceConfig extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSource(); } } ``` 4. 创建数据源上下文类,用于设置和获取当前使用的数据源: ```java public class DataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); public static void setDataSource(String dataSource) { contextHolder.set(dataSource); } public static String getDataSource() { return contextHolder.get(); } public static void clearDataSource() { contextHolder.remove(); } } ``` 5. 创建数据源切换注解,用于在方法或类上标注使用哪个数据源: ```java @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { String value() default "主数据源"; } ``` 6. 创建数据源切面类,用于根据注解切换数据源: ```java @Aspect @Component public class DataSourceAspect { @Before("@annotation(dataSource)") public void switchDataSource(JoinPoint joinPoint, DataSource dataSource) { String dataSourceName = dataSource.value(); DataSourceContextHolder.setDataSource(dataSourceName); } @After("@annotation(dataSource)") public void restoreDataSource(JoinPoint joinPoint, DataSource dataSource) { DataSourceContextHolder.clearDataSource(); } } ``` 7. 在需要使用多数据源的方法或类上使用@DataSource注解,指定使用哪个数据源: ```java @DataSource("数据源1的名称") public void method1() { // 使用数据源1执行操作 } @DataSource("数据源2的名称") public void method2() { // 使用数据源2执行操作 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值