• Hikari连接池1--初始化连接池


    基于SpringBoot 2.2.7.RELEASE 依赖的 HikariCP 3.4.3。
    源码包中源码和实际Class文件反编译代码有出入,以Class反编译代码为准。
    Hikari连接池有两篇
    Hikari连接池1–初始化连接池
    Hikari连接池2–获取和归还连接
    Hikari有两个连接池

    private final HikariPool fastPathPool;
    private volatile HikariPool pool;
    
    • 1
    • 2

    1、默认构造器

    public HikariDataSource() {
        super();
        //将 fastPathPool 置空
        fastPathPool = null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    HikariDataSource 继承 HikariConfig,super 调的是 HikariConfig 的构造方法。

    HikariDataSource 也实现了 DataSource 接口

    public HikariConfig() {
        dataSourceProperties = new Properties();
        healthCheckProperties = new Properties();
    
        minIdle = -1;
        maxPoolSize = -1;
        maxLifetime = MAX_LIFETIME;
        connectionTimeout = CONNECTION_TIMEOUT;
        validationTimeout = VALIDATION_TIMEOUT;
        idleTimeout = IDLE_TIMEOUT;
        initializationFailTimeout = 1;
        isAutoCommit = true;
    
        String systemProp = System.getProperty("hikaricp.configurationFile");
        if (systemProp != null) {
            loadProperties(systemProp);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    使用 HikariDataSource 的默认构造方法创建数据源,多次创建,其父 HikariConfig 只有一个。

    并且,这个构造器没有初始化连接池。

    2、带参构造器

    public HikariDataSource(HikariConfig configuration){
        //校验
        configuration.validate();
        //拷贝属性
        configuration.copyStateTo(this);
    
        LOGGER.info("{} - Starting...", configuration.getPoolName());
        //创建新的连接池
        pool = fastPathPool = new HikariPool(this);
        LOGGER.info("{} - Start completed.", configuration.getPoolName());
    	//设置标志
        this.seal();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    创建 HikariPool

    public HikariPool(final HikariConfig config) {
        //调用父类构造器初始化数据源
        super(config);
    	//创建bag
        this.connectionBag = new ConcurrentBag<>(this);
        //创建Semaphore锁
        this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK;
    	//创建线程池
        this.houseKeepingExecutorService = initializeHouseKeepingExecutorService();
    	//初始化连接池,向连接池里放连接
        checkFailFast();
    
        if (config.getMetricsTrackerFactory() != null) {
            setMetricsTrackerFactory(config.getMetricsTrackerFactory());
        }
        else {
            setMetricRegistry(config.getMetricRegistry());
        }
    
        setHealthCheckRegistry(config.getHealthCheckRegistry());
    
        handleMBeans(this, true);
    
        ThreadFactory threadFactory = config.getThreadFactory();
    
        final int maxPoolSize = config.getMaximumPoolSize();
        LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(maxPoolSize);
        this.addConnectionQueueReadOnlyView = unmodifiableCollection(addConnectionQueue);
        this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());
        this.closeConnectionExecutor = createThreadPoolExecutor(maxPoolSize, poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
    
        this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService);
    
        this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, housekeepingPeriodMs, MILLISECONDS);
    
        if (Boolean.getBoolean("com.zaxxer.hikari.blockUntilFilled") && config.getInitializationFailTimeout() > 1) {
            addConnectionExecutor.setCorePoolSize(Math.min(16, Runtime.getRuntime().availableProcessors()));
            addConnectionExecutor.setMaximumPoolSize(Math.min(16, Runtime.getRuntime().availableProcessors()));
    
            final long startTime = currentTime();
            while (elapsedMillis(startTime) < config.getInitializationFailTimeout() && getTotalConnections() < config.getMinimumIdle()) {
                quietlySleep(MILLISECONDS.toMillis(100));
            }
    
            addConnectionExecutor.setCorePoolSize(1);
            addConnectionExecutor.setMaximumPoolSize(1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    2.1、初始化数据源

    HikariPool的父类

    PoolBase(final HikariConfig config) {
        this.config = config;
    
        this.networkTimeout = UNINITIALIZED;
        this.catalog = config.getCatalog();
        this.schema = config.getSchema();
        this.isReadOnly = config.isReadOnly();
        this.isAutoCommit = config.isAutoCommit();
        this.exceptionOverride = UtilityElf.createInstance(config.getExceptionOverrideClassName(), SQLExceptionOverride.class);
        this.transactionIsolation = UtilityElf.getTransactionIsolation(config.getTransactionIsolation());
    
        this.isQueryTimeoutSupported = UNINITIALIZED;
        this.isNetworkTimeoutSupported = UNINITIALIZED;
        this.isUseJdbc4Validation = config.getConnectionTestQuery() == null;
        this.isIsolateInternalQueries = config.isIsolateInternalQueries();
    
        this.poolName = config.getPoolName();
        this.connectionTimeout = config.getConnectionTimeout();
        this.validationTimeout = config.getValidationTimeout();
        this.lastConnectionFailure = new AtomicReference<>();
    	//初始化数据源
        initializeDataSource();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    初始化DataSource

    private void initializeDataSource() {
        final String jdbcUrl = config.getJdbcUrl();
        final String username = config.getUsername();
        final String password = config.getPassword();
        final String dsClassName = config.getDataSourceClassName();
        final String driverClassName = config.getDriverClassName();
        final String dataSourceJNDI = config.getDataSourceJNDI();
        final Properties dataSourceProperties = config.getDataSourceProperties();
    	//DataSource 为空,创建
        DataSource ds = config.getDataSource();
        if (dsClassName != null && ds == null) {
            ds = createInstance(dsClassName, DataSource.class);
            PropertyElf.setTargetFromProperties(ds, dataSourceProperties);
        }
        else if (jdbcUrl != null && ds == null) {//一般会执行这里
            ds = new DriverDataSource(jdbcUrl, driverClassName, dataSourceProperties, username, password);
        }
        else if (dataSourceJNDI != null && ds == null) {
            try {
                InitialContext ic = new InitialContext();
                ds = (DataSource) ic.lookup(dataSourceJNDI);
            } catch (NamingException e) {
                throw new PoolInitializationException(e);
            }
        }
    
        if (ds != null) {
            //设置登录超时时间
            setLoginTimeout(ds);
            //创建网络超时执行器
            createNetworkTimeoutExecutor(ds, dsClassName, jdbcUrl);
        }
    
        this.dataSource = ds;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    创建数据源

    public DriverDataSource(String jdbcUrl, String driverClassName, Properties properties, String username, String password) {
        this.jdbcUrl = jdbcUrl;
        this.driverProperties = new Properties();
    
        for (Entry<Object, Object> entry : properties.entrySet()) {
            driverProperties.setProperty(entry.getKey().toString(), entry.getValue().toString());
        }
    
        if (username != null) {
            driverProperties.put(USER, driverProperties.getProperty("user", username));
        }
        if (password != null) {
            driverProperties.put(PASSWORD, driverProperties.getProperty("password", password));
        }
    
        if (driverClassName != null) {
            Enumeration<Driver> drivers = DriverManager.getDrivers();
            while (drivers.hasMoreElements()) {
                Driver d = drivers.nextElement();
                if (d.getClass().getName().equals(driverClassName)) {
                    driver = d;
                    break;
                }
            }
    
            if (driver == null) {
                LOGGER.warn("Registered driver with driverClassName={} was not found, trying direct instantiation.", driverClassName);
                Class<?> driverClass = null;
                ClassLoader threadContextClassLoader = Thread.currentThread().getContextClassLoader();
                try {
                    if (threadContextClassLoader != null) {
                        try {
                            driverClass = threadContextClassLoader.loadClass(driverClassName);
                            LOGGER.debug("Driver class {} found in Thread context class loader {}", driverClassName, threadContextClassLoader);
                        }
                        catch (ClassNotFoundException e) {
                            LOGGER.debug("Driver class {} not found in Thread context class loader {}, trying classloader {}",
                                         driverClassName, threadContextClassLoader, this.getClass().getClassLoader());
                        }
                    }
    
                    if (driverClass == null) {
                        driverClass = this.getClass().getClassLoader().loadClass(driverClassName);
                        LOGGER.debug("Driver class {} found in the HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());
                    }
                } catch (ClassNotFoundException e) {
                    LOGGER.debug("Failed to load driver class {} from HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());
                }
    
                if (driverClass != null) {
                    try {
                        //初始化驱动
                        driver = (Driver) driverClass.newInstance();
                    } catch (Exception e) {
                        LOGGER.warn("Failed to create instance of driver class {}, trying jdbcUrl resolution", driverClassName, e);
                    }
                }
            }
        }
    
        final String sanitizedUrl = jdbcUrl.replaceAll("([?&;]password=)[^&#;]*(.*)", "$1$2");
        try {
            if (driver == null) {
                driver = DriverManager.getDriver(jdbcUrl);
                LOGGER.debug("Loaded driver with class name {} for jdbcUrl={}", driver.getClass().getName(), sanitizedUrl);
            }
            else if (!driver.acceptsURL(jdbcUrl)) {
                throw new RuntimeException("Driver " + driverClassName + " claims to not accept jdbcUrl, " + sanitizedUrl);
            }
        }
        catch (SQLException e) {
            throw new RuntimeException("Failed to get driver instance for jdbcUrl=" + sanitizedUrl, e);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    2.2、初始化连接池

    private final ConcurrentBag<PoolEntry> connectionBag;
    //com.zaxxer.hikari.pool.HikariPool#checkFailFast
    private void checkFailFast() {
        final long initializationTimeout = config.getInitializationFailTimeout();
        if (initializationTimeout < 0) {
            return;
        }
    
        final long startTime = currentTime();
        do {
            //创建entry
            final PoolEntry poolEntry = createPoolEntry();
            //entry不为空,将entry设置到bag里面,这是初始化时创建的一条连接
            if (poolEntry != null) {
                if (config.getMinimumIdle() > 0) {
                    //添加到连接池
                    connectionBag.add(poolEntry);
                    logger.debug("{} - Added connection {}", poolName, poolEntry.connection);
                }
                else {
                    quietlyCloseConnection(poolEntry.close(), "(initialization check complete and minimumIdle is zero)");
                }
    
                return;
            }
    
            if (getLastConnectionFailure() instanceof ConnectionSetupException) {
                throwPoolInitializationException(getLastConnectionFailure().getCause());
            }
    
            quietlySleep(SECONDS.toMillis(1));
        } while (elapsedMillis(startTime) < initializationTimeout);
    
        if (initializationTimeout > 0) {
            throwPoolInitializationException(getLastConnectionFailure());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    2.2.1、创建连接

    //com.zaxxer.hikari.pool.HikariPool#createPoolEntry
    private PoolEntry createPoolEntry() {
        try {
            final PoolEntry poolEntry = newPoolEntry();
    
            final long maxLifetime = config.getMaxLifetime();
            if (maxLifetime > 0) {
                // variance up to 2.5% of the maxlifetime
                final long variance = maxLifetime > 10_000 ? ThreadLocalRandom.current().nextLong( maxLifetime / 40 ) : 0;
                final long lifetime = maxLifetime - variance;
                poolEntry.setFutureEol(houseKeepingExecutorService.schedule(
                    () -> {
                        if (softEvictConnection(poolEntry, "(connection has passed maxLifetime)", false /* not owner */)) {
                            addBagItem(connectionBag.getWaitingThreadCount());
                        }
                    },
                    lifetime, MILLISECONDS));
            }
    
            return poolEntry;
        }
        catch (ConnectionSetupException e) {
            if (poolState == POOL_NORMAL) { // we check POOL_NORMAL to avoid a flood of messages if shutdown() is running concurrently
                logger.error("{} - Error thrown while acquiring connection from data source", poolName, e.getCause());
                lastConnectionFailure.set(e);
            }
        }
        catch (Exception e) {
            if (poolState == POOL_NORMAL) { // we check POOL_NORMAL to avoid a flood of messages if shutdown() is running concurrently
                logger.debug("{} - Cannot acquire connection from data source", poolName, e);
            }
        }
    
        return null;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    创建连接

    //com.zaxxer.hikari.pool.PoolBase#newPoolEntry
    PoolEntry newPoolEntry() throws Exception {
        return new PoolEntry(newConnection(), this, isReadOnly, isAutoCommit);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    2.2.1.1、创建连接
    //com.zaxxer.hikari.pool.PoolBase#newConnection
    private Connection newConnection() throws Exception {
        final long start = currentTime();
    
        Connection connection = null;
        try {
            String username = config.getUsername();
            String password = config.getPassword();
    		//获取连接
            connection = (username == null) ? dataSource.getConnection() : dataSource.getConnection(username, password);
            if (connection == null) {
                throw new SQLTransientConnectionException("DataSource returned null unexpectedly");
            }
    		//设置连接属性
            setupConnection(connection);
            lastConnectionFailure.set(null);
            return connection;
        }
        catch (Exception e) {
            if (connection != null) {
                quietlyCloseConnection(connection, "(Failed to create/setup connection)");
            }
            else if (getLastConnectionFailure() == null) {
                logger.debug("{} - Failed to create/setup connection: {}", poolName, e.getMessage());
            }
    
            lastConnectionFailure.set(e);
            throw e;
        }
        finally {
            // tracker will be null during failFast check
            if (metricsTracker != null) {
                metricsTracker.recordConnectionCreated(elapsedMillis(start));
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    2.2.1.1.1、获取链接
    //com.zaxxer.hikari.util.DriverDataSource#getConnection
    public Connection getConnection(final String username, final String password) throws SQLException {
        final Properties cloned = (Properties) driverProperties.clone();
        if (username != null) {
            cloned.put("user", username);
            if (cloned.containsKey("username")) {
                cloned.put("username", username);
            }
        }
        if (password != null) {
            cloned.put("password", password);
        }
    	//从数据库驱动获取连接
        return driver.connect(jdbcUrl, cloned);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    2.2.1.2、设置连接属性
    //com.zaxxer.hikari.pool.PoolBase#setupConnection
    private void setupConnection(final Connection connection) throws ConnectionSetupException {
        try {
            if (networkTimeout == UNINITIALIZED) {
                networkTimeout = getAndSetNetworkTimeout(connection, validationTimeout);
            }
            else {
                setNetworkTimeout(connection, validationTimeout);
            }
    
            if (connection.isReadOnly() != isReadOnly) {
                connection.setReadOnly(isReadOnly);
            }
    
            if (connection.getAutoCommit() != isAutoCommit) {
                connection.setAutoCommit(isAutoCommit);
            }
    		//检查驱动
            checkDriverSupport(connection);
    
            if (transactionIsolation != defaultTransactionIsolation) {
                connection.setTransactionIsolation(transactionIsolation);
            }
    
            if (catalog != null) {
                connection.setCatalog(catalog);
            }
    
            if (schema != null) {
                connection.setSchema(schema);
            }
    		//执行sql
            executeSql(connection, config.getConnectionInitSql(), true);
    
            setNetworkTimeout(connection, networkTimeout);
        }
        catch (SQLException e) {
            throw new ConnectionSetupException(e);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    执行初始化sql

    //com.zaxxer.hikari.pool.PoolBase#executeSql
    private void executeSql(final Connection connection, final String sql, final boolean isCommit) throws SQLException {
        if (sql != null) {
            try (Statement statement = connection.createStatement()) {
                // connection was created a few milliseconds before, so set query timeout is omitted (we assume it will succeed)
                //执行sql
                statement.execute(sql);
            }
    
            if (isIsolateInternalQueries && !isAutoCommit) {
                if (isCommit) {
                    connection.commit();
                }
                else {
                    connection.rollback();
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    2.2.1.2、创建PoolEntry
    PoolEntry(final Connection connection, final PoolBase pool, final boolean isReadOnly, final boolean isAutoCommit) {
        this.connection = connection;
        this.hikariPool = (HikariPool) pool;
        this.isReadOnly = isReadOnly;
        this.isAutoCommit = isAutoCommit;
        this.lastAccessed = currentTime();
        this.openStatements = new FastList<>(Statement.class, 16);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    2.2.2、向bag添加连接
    private final CopyOnWriteArrayList<T> sharedList;
    //com.zaxxer.hikari.util.ConcurrentBag#add
    public void add(final T bagEntry) {
        if (closed) {
            LOGGER.info("ConcurrentBag has been closed, ignoring add()");
            throw new IllegalStateException("ConcurrentBag has been closed, ignoring add()");
        }
    	//添加到sharedList
        sharedList.add(bagEntry);
    
        // spin until a thread takes it or none are waiting
        while (waiters.get() > 0 && bagEntry.getState() == STATE_NOT_IN_USE && !handoffQueue.offer(bagEntry)) {
            Thread.yield();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    关于优化算法在线更新simulink参数时的一些注意事项
    剑指 Offer 06. 从尾到头打印链表
    2022谷粒商城学习笔记(五)文件上传功能
    你需要的免费热门API接口这里都有~
    应用程序日志管理工具
    jwt入门
    实体店主最爱的中秋活动方案,直接照搬就能轻松爆单!
    HashTable、HashMap、ConcurrentHashMap之间的区别
    HotReload for unity支持的代码修改
    Redis常用配置详解
  • 原文地址:https://blog.csdn.net/xuwenjingrenca/article/details/126911393