目录
1.7、数据源的相关配置
在数据库访问过程中,“数据源”是最重要的概念之一,目前,在市面上有很多优秀的开源数据源,例如 DBCP、C3P0、Druid、HikariCP 等等,SpringBoot默认采用了HikariCP 。
SpringBoot用来配置数据源的类为: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 {
}
它内部有五个内部类:其中有2个为配置类(数据源、数据连接池),3个为限制条件类):
-
EmbeddedDatabaseConfiguration:嵌入式数据库配置
通过
@Conditional(EmbeddedDatabaseCondition.class)
注解引入内部的限制条件类,检测容器中是否已经存在池化数据源(PooledDataSource),若不存在,通过@Import 注解引入 EmbeddedDataSourceConfiguration 类来向容器中添加一个内嵌的数据源(DataSource),若存在,则 EmbeddedDatabaseConfiguration 不能被实例化@Configuration(proxyBeanMethods = false) @Conditional(EmbeddedDatabaseCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import(EmbeddedDataSourceConfiguration.class) protected static class EmbeddedDatabaseConfiguration { }
通过@Import导入EmbeddedDataSourceConfiguration,它向容器中添加了一个 Spring Boot 内嵌的数据源
@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(DataSourceProperties.class) public class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware { private ClassLoader classLoader; @Override public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } //向容器中添加 Spring Boot 内嵌的数据源,支持 HSQL,H2 和 DERBY 三种数据库 @Bean(destroyMethod = "shutdown") public EmbeddedDatabase dataSource(DataSourceProperties properties) { //配置默认的数据源 return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseConnection.get(this.classLoader).getType()) .setName(properties.determineDatabaseName()).build(); } }
-
PooledDataSourceConfiguration:池化数据源配置
通过
@Conditional(PooledDataSourceCondition.class)
用来检测容器中是否已经存在池化数据源的,若存在,可以向容器中添加池化数据源。@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 { }
@Import 注解引入了 Hikari、Tomcat、Dbcp2、OracleUcp 和 Generic 五个数据源配置类,它们都是 DataSourceConfiguration 的内部类,作用是向容器中添加指定的数据源
@Configuration(proxyBeanMethods = false) //当前类是一个配置类; @ConditionalOnClass(HikariDataSource.class) //容器中没有用户自定义的数据源时,该配置类才会被实例化; @ConditionalOnMissingBean(DataSource.class) //必须在类路径中存在 HikariDataSource时,才会实例化。 @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true) static class Hikari { //在配置文件中配置了 spring.datasource.type = com.zaxxer.hikari.HikariDataSource或者不配置 spring.datasource.type(即默认情况)时,Hikari 才会被实例化。 @Bean @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; } }
-
PooledDataSourceCondition:合并数据源条件,主要用来检测容器中是否已经存在池化数据源(PooledDataSource)。
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 { } }
-
PooledDataSourceAvailableCondition:测试支持的连接池是否可用的Condition 。
static class PooledDataSourceAvailableCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ConditionMessage.Builder message = ConditionMessage.forCondition("PooledDataSource"); if (DataSourceBuilder.findType(context.getClassLoader()) != null) { return ConditionOutcome.match(message.foundExactly("supported DataSource")); } return ConditionOutcome.noMatch(message.didNotFind("supported DataSource").atAll()); } }
-
EmbeddedDatabaseCondition:检测何时可以使用嵌入式DataSource类型的Condition ,如果一个池化的DataSource可用,它总是优先于EmbeddedDatabase 。
static class EmbeddedDatabaseCondition extends SpringBootCondition { //数据源 URL 属性 private static final String DATASOURCE_URL_PROPERTY = "spring.datasource.url"; //合并条件 private final SpringBootCondition pooledCondition = new PooledDataSourceCondition(); // @Override 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)); } private boolean hasDataSourceUrlProperty(ConditionContext context) { Environment environment = context.getEnvironment(); if (environment.containsProperty(DATASOURCE_URL_PROPERTY)) { try { return StringUtils.hasText(environment.getProperty(DATASOURCE_URL_PROPERTY)); } catch (IllegalArgumentException ex) { // Ignore unresolvable placeholder errors } } return false; } }