Spring Boot data source configuration principle

In the process of database access, "data source" is undoubtedly one of the most important concepts. It can not only encapsulate and manage various parameters related to database access, but also manage database connection pools and improve database connection performance.

At present, there are many excellent open source data sources on the market, such as DBCP, C3P0, Druid, HikariCP and so on. In Spring Boot 2.x, the currently best performing HikariCP is used as its default data source. Next, let's introduce Spring Boot's default data source configuration and its principles.
DataSourceAutoConfiguration
We know that almost all default configurations in Spring Boot are configured through the configuration class XxxAutoConfiguration, and Spring Boot data sources are no exception. Its automatic configuration class is: DataSourceAutoConfiguration.

DataSourceAutoConfiguration includes the following five internal static classes:
EmbeddedDatabaseCondition
PooledDataSourceAvailableCondition
PooledDataSourceCondition
PooledDataSourceConfiguration (pooled data source automatic configuration class)
EmbeddedDatabaseConfiguration (embedded data source automatic configuration class)

Among them, PooledDataSourceConfiguration and EmbeddedDatabaseConfiguration are automatic configuration classes annotated with @Configuration, and the remaining three are restriction class.
EmbeddedDatabaseConfiguration
As the name suggests, EmbeddedDatabaseConfiguration is an automatic configuration class for embedded data sources. There are no methods in this class. Its main functions are implemented by introducing the EmbeddedDataSourceConfiguration class through the @Import annotation.
@Import({EmbeddedDataSourceConfiguration. class})

EmbeddedDataSourceConfiguration adds a Spring Boot embedded data source to the container, which supports HSQL, H2 and DERBY databases, and some of its codes are as follows.
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({DataSourceProperties.class})
public class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware { private ClassLoader classLoader; public EmbeddedDataSourceConfiguration() { } public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } //向Add Spring Boot embedded data source in the container @Bean( destroyMethod = "shutdown" ) public EmbeddedDatabase dataSource(DataSourceProperties properties) {











return (new EmbeddedDatabaseBuilder()).setType(EmbeddedDatabaseConnection.get(this.classLoader).getType()).setName(properties.determineDatabaseName()).build();
}
}

Through the above analysis, we know that the function of the automatic configuration class EmbeddedDatabaseConfiguration is to add an embedded data source (DataSource) to the container, but this is conditional.

A @Conditional annotation is also used on the EmbeddedDatabaseConfiguration class, which uses the internal restriction class EmbeddedDatabaseCondition of DataSourceAutoConfiguration for conditional judgment.
@Conditional({DataSourceAutoConfiguration.EmbeddedDatabaseCondition.class})

EmbeddedDatabaseCondition is mainly used to detect whether a pooled data source (PooledDataSource) already exists in the container. EmbeddedDatabaseConfiguration cannot be instantiated if there is a pooled data source in the container. EmbeddedDatabaseConfiguration can be instantiated only when there is no pooled data source in the container, and an embedded data source (EmbeddedDataSource) can be added to the container.
PooledDataSourceConfiguration
PooledDataSourceConfiguration is an automatic configuration class for pooled data sources. A @Conditional annotation is used on this class, which uses the internal restriction class PooledDataSourceCondition of DataSourceAutoConfiguration for conditional judgment.
@Conditional({DataSourceAutoConfiguration. PooledDataSourceCondition. class})

PooledDataSourceCondition, like EmbeddedDatabaseCondition, is also used to detect whether a pooled data source already exists in the container, but the difference is that PooledDataSourceConfiguration can only be instantiated and added to the container when there is a pooled data source in the container Pooled data sources.

Like EmbeddedDatabaseConfiguration, there is no method implementation in the PooledDataSourceConfiguration class, and all its functions are implemented by introducing other classes through the @Import annotation.
@Import({Hikari.class, Tomcat.class, Dbcp2.class, OracleUcp.class, Generic.class, DataSourceJmxConfiguration.class})

PooledDataSourceConfiguration introduces five data source configuration classes, Hikari, Tomcat, Dbcp2, OracleUcp, and Generic, through @Import annotations. They are all internal classes of DataSourceConfiguration, and their functions are similar, adding specified data sources to the container.

Let's take Hikari as an example for analysis. The source code of Hikari is as follows.
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({HikariDataSource.class})
@ConditionalOnMissingBean({DataSource.class})
@ConditionalOnProperty(
name = {"spring.datasource.type"},
havingValue = "com.zaxxer.hikari.HikariDataSource ",
matchIfMissing = true
)
static class Hikari { Hikari() { } @Bean @ConfigurationProperties( prefix = "spring.datasource.hikari" ) HikariDataSource dataSource(DataSourceProperties properties) {







HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}

In the Hikari class, the following annotations are mainly used:
@Configuration: Indicates that the current class is a configuration class;
@ConditionalOnMissingBean({DataSource.class}): Indicates that the configuration class will be instantiated only when there is no user-defined data source in the container ;
@ConditionalOnClass({HikariDataSource.class}) : Indicates that Hikari will be instantiated only when the HikariDataSource class exists in the classpath. The HikariDataSource class is introduced by spring-boot-starter-jdbc by default, so as long as we introduce the starter in pom.xml, Hikari will be instantiated (this is also the default use of HikariCP by Spring Boot 2.x as its data source). ;
@ConditionalOnProperty(name = {"spring.datasource.type"}, havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true): Indicates that spring.datasource.type = com is configured in the Spring Boot configuration file Hikari will be instantiated only when .zaxxer.hikari.HikariDataSource (explicitly specify the Hikari data source) or when spring.datasource.type is not configured (that is, the default).

The Hikari class adds the HikariDataSource component to the container through the @Bean annotation, and the instance object of the component is obtained by calling the createDataSource() method of DataSourceConfiguration, the code is as follows.
@Bean
@ConfigurationProperties(
prefix = "spring.datasource.hikari"
)
HikariDataSource dataSource(DataSourceProperties properties) { HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class); if (StringUtils.hasText(Name) )) { dataSource. setPoolName(properties. getName()); } return dataSource; }





In the createDataSource() method, call initializeDataSourceBuilder() of DataSourceProperties to initialize DataSourceBuilder, the source code is as follows.
protected static T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) { return properties.initializeDataSourceBuilder().type(type).build() ;

The initializeDataSourceBuilder() method creates a DataSourceBuilder object by calling the create() method of DataSourceBuilder, and sets the data source type, driver class name, connection url, user name and password in sequence according to the configuration in the Spring Boot configuration file (application.properties/yml) and other information.
public DataSourceBuilder<?> initializeDataSourceBuilder() { return DataSourceBuilder.create(this.getClassLoader()).type(this.getType()). driverClassName(this.determineDriverClassName()).url(this.determineUrl()).username( this.determineUsername()).password(this.determinePassword()); }


As mentioned above, spring.datasource.type can be configured without default, so after the createDataSource() method gets the returned DataSourceBuilder object, it needs to set its type property to HikariDataSource again, and call the build() of DataSourceBuilder method to complete the initialization of HikariDataSource.

insert image description here

Figure 1: Initializing HikariDataSource

The dataSource() method obtains the data source object, sets the name of the connection pool (name), and injects it into the container.

Figure 2: Setting the connection pool name

insert image description here

Since then, we have completed the analysis of the principle of Spring Boot data source automatic configuration.

Summary
Through the analysis of the principle of Spring Boot data source automatic configuration, we can see that
if the user does not configure the data source, if there is a HikariDataSource class in the container, Spring Boot will automatically instantiate Hikari and use it as its data source.
Spring Boot's JDBC scene starter (spring-boot-starter-data-jdbc) introduces the HikariCP data source (including the HikariDataSource class) by default through spring-boot-starter-jdbc, so Spring Boot uses HikariCP as its data source by default.

Guess you like

Origin blog.csdn.net/weixin_64842782/article/details/125106982