【HikariCP】【HikariDataSource】源码学习

Hikari目前已经是springboot的默认数据库连接池,并且以高效和轻量著称,因为代码量比较少,所以可以阅读一下,学习一下,github地址:HikariCP

HikariDataSource

成员变量

  • private final AtomicBoolean isShutdown = new AtomicBoolean();

线程安全的连接池是否关闭的标识符

  • private final HikariPool fastPathPool;

通过传入的配置创建的实际连接池的对象引用

  • private volatile HikariPool pool;

通过自身的配置创建的实际连接池的对象引用,注意这里的volatile,这个是为双重检查锁定模式使用的

构造器

  • 默认构造器
public HikariDataSource()
{
  super();
  fastPathPool = null;
}

默认构造器可以看到是将配置设置一下默认值,然后初始化一下HikariPool为null

  • 带参构造器
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();
}

首先是对传入的配置参数进行检查是否符合要求,如果符合要求将参数复制到本对象中,然后开始创建线程池,将创建的线程池的引用赋给fastPathPool,然后将是否封闭的值改成true防止被恶意修改

数据库连接池实现方法

  • public Connection getConnection() throws SQLException
@Override
public Connection getConnection() throws SQLException
{
  if (isClosed()) {
     throw new SQLException("HikariDataSource " + this + " has been closed.");
  }

  if (fastPathPool != null) {
     return fastPathPool.getConnection();
  }

  // See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
  HikariPool result = pool;
  if (result == null) {
     synchronized (this) {
        result = pool;
        if (result == null) {
           validate();
           LOGGER.info("{} - Starting...", getPoolName());
           try {
              pool = result = new HikariPool(this);
              this.seal();
           }
           catch (PoolInitializationException pie) {
              if (pie.getCause() instanceof SQLException) {
                 throw (SQLException) pie.getCause();
              }
              else {
                 throw pie;
              }
           }
           LOGGER.info("{} - Start completed.", getPoolName());
        }
     }
  }

  return result.getConnection();
}

首先检查该连接池是否已经关闭,就是成员变量的isShutdown的值。如果已经关闭,抛出已经关闭的异常。如果连接池初始化成功的话,直接调用连接池的getConnection()方法返回。如果没有初始化,那么通过自身的配置信息初始化一个数据库连接池赋给pool字段。然后用这个新创建的连接池返回连接。
这里代码那么长主要是因为用了双重检查锁定模式,防止在多线程的情况中初始化一个不完整的数据库连接池。具体双重检查锁定模式的意义和实现,作者在代码中加了它的维基百科地址:双重检查锁定模式

  • public T unwrap(Class iface) throws SQLException
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException
{
  if (iface.isInstance(this)) {
     return (T) this;
  }

  HikariPool p = pool;
  if (p != null) {
     final DataSource unwrappedDataSource = p.getUnwrappedDataSource();
     if (iface.isInstance(unwrappedDataSource)) {
        return (T) unwrappedDataSource;
     }

     if (unwrappedDataSource != null) {
        return unwrappedDataSource.unwrap(iface);
     }
  }

  throw new SQLException("Wrapped DataSource is not an instance of " + iface);
}

这个方法是为了将连接池转换成指定的数据库连接池类型,如果是的,进行强制转换后返回

  • public boolean isWrapperFor(Class<?> iface) throws SQLException
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException
{
  if (iface.isInstance(this)) {
     return true;
  }

  HikariPool p = pool;
  if (p != null) {
     final DataSource unwrappedDataSource = p.getUnwrappedDataSource();
     if (iface.isInstance(unwrappedDataSource)) {
        return true;
     }

     if (unwrappedDataSource != null) {
        return unwrappedDataSource.isWrapperFor(iface);
     }
  }

  return false;
}

这个方法是来判断当前的对象是不是指定类的实例

HikariConfigMXBean接口方法

  • public void setMetricRegistry(Object metricRegistry)
@Override
public void setMetricRegistry(Object metricRegistry)
{
  boolean isAlreadySet = getMetricRegistry() != null;
  super.setMetricRegistry(metricRegistry);

  HikariPool p = pool;
  if (p != null) {
     if (isAlreadySet) {
        throw new IllegalStateException("MetricRegistry can only be set one time");
     }
     else {
        p.setMetricRegistry(super.getMetricRegistry());
     }
  }
}

设置度量标准注册表,先调用父类HikariConfig的set方法来检查和设置,如果没有问题、连接池也初始化完成并且没有设置过,就可以进行参数的设置

  • public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory)

同上

  • public void setHealthCheckRegistry(Object healthCheckRegistry)

同上

连接池特殊方法

  • public boolean isRunning()
public boolean isRunning()
{
  return pool != null && pool.poolState == POOL_NORMAL;
}

检查连接池是否正在运行,判断条件是连接池存在并且状态是正常状态

  • public void evictConnection(Connection connection)
public void evictConnection(Connection connection)
{
  HikariPool p;
  if (!isClosed() && (p = pool) != null && connection.getClass().getName().startsWith("com.zaxxer.hikari")) {
     p.evictConnection(connection);
  }
}

将指定的连接从连接池中去除。判断条件是连接池没有关闭并且连接池存在并且这个连接是hikari数据库连接池的连接,以上为真的情况下,调用HikariPool的方法去除该连接

  • public void close()
@Override
public void close()
{
  if (isShutdown.getAndSet(true)) {
     return;
  }

  HikariPool p = pool;
  if (p != null) {
     try {
        LOGGER.info("{} - Shutdown initiated...", getPoolName());
        p.shutdown();
        LOGGER.info("{} - Shutdown completed.", getPoolName());
     }
     catch (InterruptedException e) {
        LOGGER.warn("{} - Interrupted during closing", getPoolName(), e);
        Thread.currentThread().interrupt();
     }
  }
}

关闭连接池,先判断是否已经关闭,如果是的就结束,如果不是,调用HikariPool的shutdown()方法进行关闭。这里比较特殊的是getAndSet()这个方法,因为涉及到原子类的赋值和取值,所以稍微有一点复杂

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章