Spring Boot 自动配置 : DataSourceAutoConfiguration

本文解析了SpringBoot中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));
		}

	}

}

<think> 我们需要回答关于Spring Boot自动配置流程的问题,并在最后按照规则提出3-5个相关问题。 回答要求使用中文,并且在末尾必须包含“§§相关问题§§”开头的问题列表。 Spring Boot自动配置流程的核心是尝试根据类路径、已存在的Bean定义和属性配置等条件自动配置应用程序。以下是主要步骤: 1. **启动类和@SpringBootApplication注解**:Spring Boot应用通常以带有`@SpringBootApplication`注解的类作为入口。该注解组合了三个核心注解: - `@SpringBootConfiguration`:标记为配置类。 - `@ComponentScan`:自动扫描当前包及其子包下的组件。 - `@EnableAutoConfiguration`:启用自动配置机制。 2. **@EnableAutoConfiguration的作用**:该注解通过`@Import`导入了`AutoConfigurationImportSelector`类。该类会读取`META-INF/spring.factories`文件中定义的自动配置类列表(key为`org.springframework.boot.autoconfigure.EnableAutoConfiguration`)。 3. **加载自动配置类**:`AutoConfigurationImportSelector`使用SpringFactoriesLoader加载所有自动配置类(如DataSourceAutoConfiguration、WebMvcAutoConfiguration等)。这些配置类通常带有`@Configuration`注解,并包含条件注解(如`@ConditionalOnClass`、`@ConditionalOnMissingBean`)来控制是否生效。 4. **条件注解评估**:每个自动配置类中包含的条件注解由`ConditionEvaluator`进行评估。例如: - `@ConditionalOnClass`:当类路径中存在指定类时才生效。 - `@ConditionalOnMissingBean`:当容器中不存在指定Bean时才生效。 这样确保了自动配置只在满足特定条件时应用,避免与用户自定义配置冲突。 5. **创建和注册Bean**:满足条件的自动配置类会向容器中注册Bean。例如,当类路径有H2数据库时,DataSourceAutoConfiguration自动配置内存数据源。 6. **属性绑定**:自动配置类通常会结合`@ConfigurationProperties`将属性文件(如application.properties)中的值绑定到配置Bean上,从而实现外部化配置。 整个过程在Spring应用上下文刷新阶段完成,最终实现“约定优于配置”,简化开发。 §§相关问题§§ 1. Spring Boot中`@Conditional`注解的工作原理是什么? 2. 如何自定义一个Spring Boot自动配置类? 3. 在什么情况下自动配置会失效,如何排查? 4. Spring Boot自动配置与显式配置(如@Bean)的优先级顺序是怎样的? </think> ### Spring Boot自动配置流程 Spring Boot自动配置是其核心特性之一,旨在根据项目依赖和配置自动装配Bean,减少手动配置。其流程如下: 1. **启动入口与注解触发** - 通过`@SpringBootApplication`注解标记主类,该注解组合了三个核心功能: - `@SpringBootConfiguration`:标识为配置类 - `@ComponentScan`:扫描当前包及子包的组件(如`@Controller`, `@Service`) - `@EnableAutoConfiguration`:**启用自动配置的关键注解**,通过`@Import`导入`AutoConfigurationImportSelector`类 2. **加载自动配置类** - `AutoConfigurationImportSelector`调用`SpringFactoriesLoader.loadFactoryNames()`方法 - 从所有JAR包的`META-INF/spring.factories`文件中读取`org.springframework.boot.autoconfigure.EnableAutoConfiguration`键对应的配置类列表 - 例如:`spring-boot-autoconfigure.jar`中定义`DataSourceAutoConfiguration`、`WebMvcAutoConfiguration`等 3. **条件化配置评估** 每个自动配置类包含**条件注解**,由`ConditionEvaluator`在运行时评估: - `@ConditionalOnClass`:类路径存在指定类时生效(如存在`Servlet.class`才启用Web配置) - `@ConditionalOnMissingBean`:容器无该类型Bean时生效(避免覆盖用户自定义Bean) - `@ConditionalOnProperty`:匹配配置文件属性(如`spring.datasource.url`) ```java @Configuration @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) public class DataSourceAutoConfiguration { // 自动配置数据源 } ``` 4. **Bean注册与属性绑定** - 满足条件的配置类通过`@Bean`方法向Spring容器注册组件 - 结合`@ConfigurationProperties`将`application.properties`中的属性(如`server.port=8080`)绑定到Bean - 示例:`ServerProperties`类绑定`server.*`前缀属性 5. **执行顺序控制** - 通过`@AutoConfigureOrder`、`@AutoConfigureBefore`等注解控制配置类的加载顺序 - 例如:`AopAutoConfiguration`需在数据源配置前加载 整个过程在**应用上下文刷新阶段**(`AbstractApplicationContext.refresh()`)完成,最终实现"约定优于配置"。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值