【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()這個方法,因爲涉及到原子類的賦值和取值,所以稍微有一點複雜

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