HikariCP数据库连接池实战
上QQ阅读APP看书,第一时间看更新

3.2 SpringBoot数据库连接池加载顺序剖析

HikariCP是Spring Boot 2.x版本官方宣布默认的数据库连接池,SpringBoot对HikariCP的采纳也从侧面说明HikariCP在使用广泛性、认可度、性能、稳定性等方面是经得起检验的,也表明HikariCP的应用前景和未来发展是一片光明。

如图3-2所示,在SpringBoot当前最新2.x版本https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database的文档中也强烈建议使用HikariCP作为默认的数据库连接池。文档中是这么描述的:我们更喜欢HikariCP的性能和并发性,如果HikariCP可用,我们总是选择它;否则,如果Tomcat池DataSource可用,我们将使用它;如果HikariCP和Tomcat数据库连接池都不可用,并且Commons DBCP2可用,我们就会使用它。当然,用户也可以通过设置spring.datasource.type属性来绕过上述使用顺序,进而指定想要使用的数据库连接池。

图3-2 SpringBoot最新版本建议使用HikariCP

当然,如果这维服务使用spring-boot-starter-jdbc或者spring-boot-starter-data-jpa的starter,会自动获得HikariCP的依赖。

其实Spring Boot 1.5.x是默认使用tomcat-jdbc作为连接池的,如下是其寻找连接池顺序的规则:Tomcat pool → HikariCP → Commons DBCP → Commons DBCP2。然而在其2.x版本中,HikariCP被提升为默认的数据库连接池,数据库连接池的默认配置顺序是HikariCP → Tomcat pool → Commons DBCP2。接下来,我们就从源码角度给读者详细介绍这个规则的原理。

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration是Spring Boot 2.0.3.Release版本中的加载数据源的核心类。在该类中,PooledDataSource-Configuration是需要重点关注的,它决定了连接池的选择。我们可以看到图3-2中的注解包含了HikariCP、Tomcat、DBCP2等主流连接池,选择连接池的不同,application. properties配置也不同。

        @Configuration
        @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
        @EnableConfigurationProperties(DataSourceProperties.class)
        @Import({ DataSourcePoolMetadataProvidersConfiguration.class,
                DataSourceInitializationConfiguration.class })
        public class DataSourceAutoConfiguration {
            @Configuration
            @Conditional(EmbeddedDatabaseCondition.class)
            @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
            @Import(EmbeddedDataSourceConfiguration.class)
            protected static class EmbeddedDatabaseConfiguration {}
            @Configuration
            @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 {}

在上述PooledDataSourceCondition的代码中,PooledDataSourceAvailableCondition有一段findType的代码用来加载资源文件。

        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;
            }

而这里的常量数组DATA_SOURCE_TYPE_NAMES就是关键,在Spring Boot 2.x的定义如下:

        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" };

在findType()方法中,for循环顺序遍历数组,加载到哪个类就使用哪个类的连接池,所以就是HikariCP → Tomcat pool → Commons DBCP2这样的顺序。

同理,在1.5.3.Release版本的SpringBoot的数组也是这么定义的,所以就是Tomcat Pool → HikariCP → Commons DBCP → Commons DBCP2的顺序。

        private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
                    "org.apache.tomcat.jdbc.pool.DataSource",
                    "com.zaxxer.hikari.HikariDataSource",
                    "org.apache.commons.dbcp.BasicDataSource", // deprecated
                    "org.apache.commons.dbcp2.BasicDataSource" };

所以若要在SpringBoot 1.5.3.Release版本中使用HikariCP,除了在spring.datasource. type属性中设置以外,还有一个简单的方法就是Maven依赖排除Tomcat-JDBC。

SpringBoot 2.0发布的时候,官方也发布了“db方面,默认引入了HikariCP,替代了之前的Tomcat-Pool作为底层的数据库连接池。对比Tomcat-Pool, HikariCP拥有更好的性能,总而言之就是提高了db的访问速度”这样的版本变更信息。读到这里读者应该能够清晰地理解SpringBoot在数据库连接池选型这件事上的来龙去脉了。