Spring Boot 自动配置 : DataSourceAutoConfiguration

概述

DataSourceAutoConfigurationSpring Boot关于关系型数据库数据源的自动配置,目的是在开发人员没有自定义数据源DataSource bean组件时,根据开发人员所引入的包自动定义DataSource bean组件。

如果开发人员使用的时嵌入式数据库H2,Derby或者HSQL,则会使用EmbeddedDataSourceConfiguration定义数据源bean,实现了接口EmbeddedDatabase

否则,如果开发人员使用的不是嵌入式数据库,则会检测数据库连接组件是否支持连接池,支持的话进而使用PooledDataSourceConfiguration定义数据源beanPooledDataSourceConfiguration会参考spring.datasource.type参数指定的数据源类以及数据源类的存在性定义相应的数据源bean :

  • com.zaxxer.hikari.HikariDataSource
  • org.apache.tomcat.jdbc.pool.DataSource
  • org.apache.commons.dbcp2.BasicDataSource

缺省情况下Spring Boot使用hikari数据源。

源代码

源代码版本 : spring-boot-autoconfigure-2.1.3.RELEASE

package org.springframework.boot.autoconfigure.jdbc;

// 省略 import 行

/**
 * EnableAutoConfiguration Auto-configuration for DataSource.
 *
 */
@Configuration
// 仅在类 DataSource, EmbeddedDatabaseType 存在于 classpath 上时才生效,
// 这两个类属于包 spring-jdbc
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
// 确保前缀为 spring.datasource 的配置属性项被加载到 bean DataSourceProperties
@EnableConfigurationProperties(DataSourceProperties.class)
// 1. 导入 DataSourcePoolMetadataProvidersConfiguration , 该配置类根据
// 开发人员引入的数据库连接池实现提供相应的 DataSourcePoolMetadataProvider
// 2. 导入 DataSourceInitializationConfiguration, 该配置类会 :
// 2.1 导入 bean DataSourceInitializerInvoker,用于执行 schema-*.sql,data-*.sql
// 2.2 dataSourceInitializerPostProcessor DataSourceInitializerPostProcessor
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
		DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {

    // 内嵌配置类
	@Configuration
    // 仅在嵌入式数据库被使用时才生效
    // 嵌入式数据库这里指的是 h2, derby, 或者 hsql
	@Conditional(EmbeddedDatabaseCondition.class)
    // 仅在没有类型为 DataSource/XADataSource 的 bean 定义时才生效
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    // 导入嵌入式数据库有关的数据源配置
    // 提供前所使用的嵌入式数据库的数据源 bean EmbeddedDatabase
	@Import(EmbeddedDataSourceConfiguration.class)
	protected static class EmbeddedDatabaseConfiguration {

	}

    // 内嵌配置类
	@Configuration
    // 仅在类 PooledDataSourceCondition 条件满足时生效 ,
    // PooledDataSourceCondition 会检测所使用的数据源组件是否支持连接池
	@Conditional(PooledDataSourceCondition.class)
    // 仅在没有类型为 DataSource/XADataSource 的 bean 定义时才生效
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    // 导入针对不同数据库类型数据源连接组件的数据源配置,这些配置仅在使用了相应的数据源连接
    // 组件时才生效,一般开发人员只使用其中一种,所以也就只会有一个生效。
    // 这些配置的目的都是为了定义一个 数据源 bean dataSource
	@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
			DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
			DataSourceJmxConfiguration.class })
	protected static class PooledDataSourceConfiguration {

	}

	/**
	 * AnyNestedCondition that checks that either spring.datasource.type
	 * is set or PooledDataSourceAvailableCondition applies.
	 */
	static class PooledDataSourceCondition extends AnyNestedCondition {

		PooledDataSourceCondition() {
			super(ConfigurationPhase.PARSE_CONFIGURATION);
		}

		@ConditionalOnProperty(prefix = "spring.datasource", name = "type")
		static class ExplicitType {

		}

		@Conditional(PooledDataSourceAvailableCondition.class)
		static class PooledDataSourceAvailable {

		}

	}

	/**
	 * Condition to test if a supported connection pool is available.
	 */
	static class PooledDataSourceAvailableCondition extends SpringBootCondition {

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context,
				AnnotatedTypeMetadata metadata) {
			ConditionMessage.Builder message = ConditionMessage
					.forCondition("PooledDataSource");
			if (getDataSourceClassLoader(context) != null) {
				return ConditionOutcome
						.match(message.foundExactly("supported DataSource"));
			}
			return ConditionOutcome
					.noMatch(message.didNotFind("supported DataSource").atAll());
		}

		/**
		 * Returns the class loader for the DataSource class. Used to ensure that
		 * the driver class can actually be loaded by the data source.
		 * @param context the condition context
		 * @return the class loader
		 */
		private ClassLoader getDataSourceClassLoader(ConditionContext context) {
			Class<?> dataSourceClass = DataSourceBuilder
					.findType(context.getClassLoader());
			return (dataSourceClass != null) ? dataSourceClass.getClassLoader() : null;
		}

	}

	/**
	 * Condition to detect when an embedded DataSource type can be used.
	 * If a pooled DataSource is available, it will always be preferred to an
	 * EmbeddedDatabase.
	 */
	static class EmbeddedDatabaseCondition extends SpringBootCondition {

		private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context,
				AnnotatedTypeMetadata metadata) {
			ConditionMessage.Builder message = ConditionMessage
					.forCondition("EmbeddedDataSource");
			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));
		}

	}

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值