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