spring boot 中关于jdbc的自动化配置如下:
我们将依次解析DataSourceAutoConfiguration,JdbcTemplateAutoConfiguration,DataSourceTransactionManagerAutoConfiguration.下面我们开始吧
DataSourceAutoConfiguration声明的注解如下:
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
parse过程:
由于DataSourceAutoConfiguration有3个配置内部类(声明有@Configuration注解的内部类),依次会先parse其内部类:
TomcatDataSourceJmxConfiguration:
TomcatDataSourceJmxConfiguration 声明的注解如下:
@ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled")
@ConditionalOnClass(name = "org.apache.tomcat.jdbc.pool.DataSourceProxy")
@Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class)
@ConditionalOnMissingBean(name = "dataSourceMBean")
@Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class)–> 通过DataSourceAvailableCondition进行判断.代码如下:
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage
.forCondition("DataSourceAvailable");
// 1. 如果BeanFactory中存在DataSource类型的bean或者存在XADataSource类型的bean时返回匹配
if (hasBean(context, DataSource.class)
|| hasBean(context, XADataSource.class)) {
return ConditionOutcome
.match(message.foundExactly("existing data source bean"));
}
// 2. 只要 pooledCondition,embeddedCondition 中任意一个满足,则返回匹配
if (anyMatches(context, metadata, this.pooledCondition,
this.embeddedCondition)) {
return ConditionOutcome.match(message
.foundExactly("existing auto-configured data source bean"));
}
// 3. 返回不匹配
return ConditionOutcome
.noMatch(message.didNotFind("any existing data source bean").atAll());
}
只要 pooledCondition,embeddedCondition 中任意一个满足,则返回匹配
PooledDataSourceCondition 判断逻辑如下:
如果在当前类路径下存在
中的任意一个时匹配.
只要第1,2点任意一个匹配,则返回匹配
embeddedCondition 判断逻辑如下:
返回不匹配
因此,该配置类TomcatDataSourceJmxConfiguration在默认情况下是不生效的.
如果该配置生效的话,由于该类有一个被@Bean注解的方法:
@Bean
public Object dataSourceMBean(DataSource dataSource) {
if (dataSource instanceof DataSourceProxy) {
try {
return ((DataSourceProxy) dataSource).createPool().getJmxPool();
}
catch (SQLException ex) {
logger.warn("Cannot expose DataSource to JMX (could not connect)");
}
}
return null;
}
PooledDataSourceConfiguration:
PooledDataSourceConfiguration 注解如下:
@Configuration
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Hikari.class,
DataSourceConfiguration.Dbcp.class, DataSourceConfiguration.Dbcp2.class,
DataSourceConfiguration.Generic.class })
@Conditional(PooledDataSourceCondition.class)–>
如果在当前类路径下存在
任意一个时生效
1,2 点任意一个匹配返回匹配
由于该类没有内部类,声明@Bean方法,只有@Import注解,因此,会调用ConfigurationClassParser#processImports依次处理之:
Tomcat 不是ImportSelector,ImportBeanDefinitionRegistrar的实例,因此会调用ConfigurationClassParser#processConfigurationClass 来处理.
Tomcat 注解如下:
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
* 由于,我们一般都会加入spring-boot-starter-jdbc,而该项目依赖了tomcat-jdbc,因此,该配置默认生效*
Tomcat中只有一个@Bean方法,代码如下:
@Bean
@ConfigurationProperties(prefix = "spring.datasource.tomcat")
public org.apache.tomcat.jdbc.pool.DataSource dataSource(
DataSourceProperties properties) {
org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(
properties, org.apache.tomcat.jdbc.pool.DataSource.class);
DatabaseDriver databaseDriver = DatabaseDriver
.fromJdbcUrl(properties.determineUrl());
String validationQuery = databaseDriver.getValidationQuery();
if (validationQuery != null) {
dataSource.setTestOnBorrow(true);
dataSource.setValidationQuery(validationQuery);
}
return dataSource;
}
Hikari–> 同样会调用ConfigurationClassParser#processConfigurationClass 来处理:
注解如下:
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
由于默认情况下,没有依赖Hikari相关的jar包,因此该配置不会生效
如果生效的话,则会激活配置,该配置类只有一个@Bean方法,如下:
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {
return createDataSource(properties, HikariDataSource.class);
}
Dbcp,Dbcp2,Generic 这3个内部类的处理和Hikari一样,都是默认不生效的,如果生效的化,会注册1个id为dataSource,类型为相应数据库连接池类型的bean,节约篇幅,这里就不赘述了.
EmbeddedDatabaseConfiguration
EmbeddedDatabaseConfiguration注解如下:
@Configuration
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
由于默认情况下是不满足@Conditional(EmbeddedDatabaseCondition.class)的条件,因此该配置不会被解析,因此也就不解析了这里.
处理完DataSourceAutoConfiguration的配置内部类之后,由于DataSourceAutoConfiguration有如下注解:
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
因此会执行ConfigurationClassParser#processImports
@EnableConfigurationProperties(DataSourceProperties.class) –> 导入了EnableConfigurationPropertiesImportSelector,又由于该类是ImportSelector的实现,因此会调用其selectImports方法,将返回的ConfigurationPropertiesBeanRegistrar,ConfigurationPropertiesBindingPostProcessorRegistrar在次调用processImports进行处理.(关于@EnableConfigurationProperties的解析,我们已经见过很多次了)
ConfigurationPropertiesBeanRegistrar, ConfigurationPropertiesBindingPostProcessorRegistrar由于都是ImportBeanDefinitionRegistrar的实例,因此会将其加入到DataSourceAutoConfiguration所对应的ConfigurationClass中的importBeanDefinitionRegistrars
DataSourcePoolMetadataProvidersConfiguration,不是ImportSelector,ImportBeanDefinitionRegistrar的实例,因此会将其按照一个配置类来进行解析:
DataSourcePoolMetadataProvidersConfiguration中只声明了4个配置类,其中默认生效的是TomcatDataSourcePoolMetadataProviderConfiguration.而在TomcatDataSourcePoolMetadataProviderConfiguration中声明了一个@Bean方法.如下:
@Bean
public DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() {
return new DataSourcePoolMetadataProvider() {
@Override
public DataSourcePoolMetadata getDataSourcePoolMetadata(
DataSource dataSource) {
if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource) {
return new TomcatDataSourcePoolMetadata(
(org.apache.tomcat.jdbc.pool.DataSource) dataSource);
}
return null;
}
};
}
注册id为tomcatPoolDataSourceMetadataProvider,类型为DataSourcePoolMetadataProvider的bean
DataSourcePoolMetadataProvidersConfiguration 中各内部类下面列出的一个表格:
类名 | 激活条件 | beanid |
---|---|---|
TomcatDataSourcePoolMetadataProviderConfiguration | 在类路径下存在org.apache.tomcat. jdbc.pool. DataSource | id为tomcatPoolDataSourceMetadataProvider |
HikariPoolDataSourceMetadataProviderConfiguration | 在类路径下存在HikariDataSource | hikariPoolDataSourceMetadataProvider |
CommonsDbcpPoolDataSourceMetadataProviderConfiguration | 在类路径下存在org.apache.commons.dbcp.BasicDataSource | commonsDbcpPoolDataSourceMetadataProvider |
CommonsDbcp2PoolDataSourceMetadataProviderConfiguration | 在类路径下存在BasicDataSource | commonsDbcp2PoolDataSourceMetadataProvider |
ps: 它们注册的bean类型都是DataSourcePoolMetadataProvider
处理完@Import后,DataSourceAutoConfiguration只有1个@Bean方法,如下:
@Bean
@ConditionalOnMissingBean
public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties,
ApplicationContext applicationContext) {
return new DataSourceInitializer(properties, applicationContext);
}
加载(ConfigurationClassBeanDefinitionReader#loadBeanDefinitions):
DataSourceConfiguration$Tomcat:
由于是被PooledDataSourceConfiguration导入的,因此会执行ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass进行注册,id为tomcat.
由于该类声明了1个@Bean方法,因此会调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod 进行注册
PooledDataSourceConfiguration:
TomcatDataSourcePoolMetadataProviderConfiguration:
DataSourcePoolMetadataProvidersConfiguration:
DataSourceAutoConfiguration:
由于DataSourceAutoConfiguration对应的ConfigurationClass中importBeanDefinitionRegistrars不为空,因此会调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars,在该方法中会遍历importBeanDefinitionRegistrars,依次调用其registerBeanDefinitions方法.
ConfigurationPropertiesBindingPostProcessorRegistrar–>如果beanFactory中不存在id为org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor的bean,则注册如下bean:
DataSourceInitializerPostProcessor$Registrar,代码如下:
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(BEAN_NAME)) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DataSourceInitializerPostProcessor.class);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// We don't need this one to be post processed otherwise it can cause a
// cascade of bean instantiation that we would rather avoid.
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
}
如果BeanDefinitionRegistry中不存在id为dataSourceInitializerPostProcessor的bean,则注册一个id为dataSourceInitializerPostProcessor,类型为DataSourceInitializerPostProcessor,角色为内部使用的bean.并将其设置为synthetic,这是因为如果不这样做,就会导致一系列的bean初始化.
JdbcTemplateAutoConfiguration注解如下:
@Configuration
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
JdbcTemplateAutoConfiguration 比较简单,没有内部类,只有两个被@bean注解的方法:
jdbcTemplate方法,注册了一个id为jdbcTemplate,类型为JdbcTemplate的bean,代码如下:
@Bean
@Primary
@ConditionalOnMissingBean(JdbcOperations.class)
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(this.dataSource);
}
namedParameterJdbcTemplate方法,代码如下:
@Bean
@Primary
@ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
return new NamedParameterJdbcTemplate(this.dataSource);
}
DataSourceTransactionManagerAutoConfiguration 注解如下:
@Configuration
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
parse过程:
DataSourceTransactionManagerAutoConfiguration 由于有内部类,因此会先parse其内部类–> DataSourceTransactionManagerConfiguration.
DataSourceTransactionManagerConfiguration有如下注解:
@Configuration
@ConditionalOnSingleCandidate(DataSource.class)
DataSourceTransactionManagerConfiguration只有一个被@Bean注解的方法:
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
public DataSourceTransactionManager transactionManager(
DataSourceProperties properties) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(
this.dataSource);
if (this.transactionManagerCustomizers != null) {
this.transactionManagerCustomizers.customize(transactionManager);
}
return transactionManager;
}
由于@EnableConfigurationProperties(DataSourceProperties.class)其元注解中通过@Import(EnableConfigurationPropertiesImportSelector.class) 导入了EnableConfigurationPropertiesImportSelector.因此会在ConfigurationClassParser#processImports方法依次处理EnableConfigurationPropertiesImportSelector#selectImports的返回值–>ConfigurationPropertiesBeanRegistrar.class,ConfigurationPropertiesBindingPostProcessorRegistrar.class。
加载(ConfigurationClassBeanDefinitionReader#loadBeanDefinitions):
DataSourceTransactionManagerConfiguration:
由于该配置是被DataSourceTransactionManagerAutoConfiguration导入的,因此会执行ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法进行注册,id为dataSourceTransactionManagerConfiguration.
由于DataSourceTransactionManagerAutoConfiguration有一个被@bean注解的方法–>transactionManager.因此会调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod进行注册
DataSourceTransactionManagerAutoConfiguration:
在解析过程中,由于向DataSourceTransactionManagerAutoConfiguration对应的ConfigurationClass中添加了2个importBeanDefinitionRegistrars,因此会调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars
ConfigurationPropertiesBindingPostProcessorRegistrar–> 如果beanFactory中不存在id为org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor的bean,则注册如下bean: