本文主要介绍
1. SpringBoot使用数据源配置方式;
2. SpringBoot默认连接池及自动配置原理(HikariCP);
3. SpringBoot替换默认连接池配置方式;
4. SpringBoot整合Druid连接池;
1. SpringBoot使用数据源配置方式
1.配置数据库驱动(Mysql为例)
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
2. SpringBoot核心配置文件中配置数据库连接信息
spring.datasource.url=jdbc:mysql:///test_mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=123456
3. 配置spring-boot-starter-jdbc
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
2. SpringBoot默认连接池及自动配置原理
SpringBoot 官方提供了三种数据库连接池 HikariCP, Commons DBCP2, Tomcat JDBC Connection Pool
默认使用的连接池是 HikariCP.
1. spring.factories中EnableAutoConfiguration中定义了数据源配置类:
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration ;
@Configuration(proxyBeanMethods = false) @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @EnableConfigurationProperties(DataSourceProperties.class) @Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class }) public class DataSourceAutoConfiguration { @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 { } static class PooledDataSourceCondition extends AnyNestedCondition { @ConditionalOnProperty(prefix = "spring.datasource", name = "type") static class ExplicitType { } @Conditional(PooledDataSourceAvailableCondition.class) static class PooledDataSourceAvailable { } }
2. DataSourceAutoConfiguration内部类PooledDataSourceConfiguration也是配置类PooledDataSourceConfiguration 中import了 DataSourceConfiguration下的Hikari,Tomcat,Dbcp2,Generic多个内部类
abstract class DataSourceConfiguration {
protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) { // 使用DataSourceBuilder 建造数据源,利用反射创建type数据源,然后绑定相关属性 return (T) properties.initializeDataSourceBuilder().type(type).build(); } /** * Tomcat Pool DataSource configuration. */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true) static class Tomcat { @Bean @ConfigurationProperties(prefix = "spring.datasource.tomcat") 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 DataSource configuration. * //2.0 之后默认默认使用 hikari 连接池 */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(HikariDataSource.class) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true) static class 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; } } /** * DBCP DataSource configuration. */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true) static class Dbcp2 { @Bean @ConfigurationProperties(prefix = "spring.datasource.dbcp2") org.apache.commons.dbcp2.BasicDataSource dataSource(DataSourceProperties properties) { return createDataSource(properties, org.apache.commons.dbcp2.BasicDataSource.class); } } /** * Generic DataSource configuration. * //自定义连接池 接口 spring.datasource.type 配置 */ @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic { @Bean DataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().build(); } }
3. 在 spring-boot-starter-jdbc 中,默认导入了HikariCP的jar,则DataSourceConfiguration中内部类 Hikari 条件注解生效,会执行
DataSourceConfiguration中的 createDataSource()方法
<artifactId>spring-boot-starter-jdbc</artifactId>
<name>Spring Boot JDBC Starter</name>
<description>Starter for using JDBC with the HikariCP connection pool</description>
<properties>
<main.basedir>${basedir}/../../..</main.basedir>
</properties>
<scm>
<url>${git.url}</url>
<connection>${git.connection}</connection>
<developerConnection>${git.developerConnection}</developerConnection>
</scm>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
</dependencies>
4. createDataSource方法调用了 getType()获取连接池类型;当配置文件中配置了spring.datasource.type 时,就加载配置的数据库连接池类型,如果没有配置就 调用findType(this.classLoader); 从DATA_SOURCE_TYPE_NAMES 中返回第一个类型即: com.zaxxer.hikari.HikariDataSource"
createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) { return (T) properties.initializeDataSourceBuilder().type(type).build();
}
DataSourceBuilder{ public T build() { Class<? extends DataSource> type = getType(); DataSource result = BeanUtils.instantiateClass(type); maybeGetDriverClassName(); bind(result); return (T) result; }
private Class<? extends DataSource> getType() { //如果没有配置type 则为空 默认选择 findType Class<? extends DataSource> type = (this.type != null) ? this.type : findType(this.classLoader); if (type != null) { return type; } throw new IllegalStateException("No supported DataSource type found"); }public static Class<? extends DataSource> findType(ClassLoader classLoader) { for (String name : DATA_SOURCE_TYPE_NAMES) { try { return (Class<? extends DataSource>) ClassUtils.forName(name, classLoader); } catch (Exception ex) { // Swallow and continue } } return null; }private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] { "com.zaxxer.hikari.HikariDataSource", "org.apache.tomcat.jdbc.pool.DataSource", "org.apache.commons.dbcp2.BasicDataSource" };
3. SpringBoot替换默认连接池配置方式
1. 改用Commons DBCP2,移除 hikari 依赖引入DBCP2依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <exclusions> <exclusion> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> </dependency>
2. 改用Tomcat JDBC Connection Pool 除 hikari 依赖引入tomcat-jdbc依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <exclusions> <exclusion> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> </dependency>
4. SpringBoot整合Druid连接池
1. 引入Durid依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency>
2. 增加DataSources配置类
@Configuration public class DruidConfig { @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource druid() { return new DruidDataSource(); } }
3. 配置数据源信息
spring: datasource: username: root password: 123456 url: jdbc:mysql:///test_mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver initialization-mode: always # 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource # 数据源其他配置 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
4. 引入log4j适配器(springBoot2.0后日志框架不再使用log4j,而是logback)
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency>