Druid源码阅读一

一、什么是druid连接池

Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能。功能强大,能防SQL注入,内置Loging能诊断Hack应用行为。

1.1、竞品分析

功能类别

功能

Druid

HikariCP

DBCP

Tomcat-jdbc

C3P0

性能

PSCache

LRU

SLB负载均衡支持

稳定性

ExceptionSorter

扩展

扩展

Filter

JdbcIntercepter

监控

监控方式

jmx/log/http

jmx/metrics

jmx

jmx

jmx

支持SQL级监控

Spring/Web关联监控

诊断支持

LogFilter

连接泄露诊断

logAbandoned

安全

SQL防注入

支持配置加密

1.2、几个概念

JDBC:Java Database Connectivity, Java链接数据库和执行SQL 语句的API

JNDI:Java Naming and Directory Interface ,Java命名和目录接口,JNDI是指使用是指使用源连接数据库的方式,可以简单理解成所有Data Source的集合

DBCP:Database Connection Pool, 数据库连接池。数据库连接池就是链接数据库的进程/线程的集合

Data Source: 数据源。就是将IP、数据库、用户名、密码封装起来对外只提供一个JNDI名称,在应用中只需要调用JNDI就可以连接数据库,而不需要写入用户名和密码

以上几个概念组成了目前主流数据库的交互流程

1、应用程序通过JNDI服务查找对应的Data Source

2、通过Data Source向DBCP发起数据库连接

3、DBCP根据自身策略分配资源利用JDBC连接数据库,建立Connect

4、通过Connect与数据库进行交互

 

二、源码分析

2.1、配置分析

2.2、getConnection总流程

2.3、源码分析

最核心的类的DruidDataResource,DruidDataResource里面有三个核心的内部类CreateConnectTask,CreateConnectionThread,DestroyConnecttionThread。从getConnection获取连接作为入口,我们可以快速看到

public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
        // 次数会初始化CreateConnectThread和DestoryConnectionThread守护线程
        init();

        if (filters.size() > 0) {
            FilterChainImpl filterChain = new FilterChainImpl(this);
            return filterChain.dataSource_connect(this, maxWaitMillis);
        } else {
            return getConnectionDirect(maxWaitMillis);
        }
    }
private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException {
    DruidConnectionHolder holder;
    ...
    for (boolean createDirect = false;;) {
        ...
        // 最大连接数大于0
        if (maxWait > 0) {
            // 从连接池队列中获取一个连接
           holder = pollLast(nanos);
        } else {
           holder = takeLast();
        }
        ...
    } 
    ...
}
private DruidConnectionHolder pollLast(long nanos) throws InterruptedException, SQLException {
        long estimate = nanos;

        for (;;) {
            // 连接池内连接大于0
             if (poolingCount == 0) {
                emptySignal(); // send signal to CreateThread create connection

                if (failFast && isFailContinuous()) {
                    throw new DataSourceNotAvailableException(createError);
                }

                if (estimate <= 0) {
                    waitNanosLocal.set(nanos - estimate);
                    return null;
                }

                notEmptyWaitThreadCount++;
                if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) {
                    notEmptyWaitThreadPeak = notEmptyWaitThreadCount;
                }

                try {
                    long startEstimate = estimate;
                    estimate = notEmpty.awaitNanos(estimate); // signal by
                                                              // recycle or
                                                              // creator
                    notEmptyWaitCount++;
                    notEmptyWaitNanos += (startEstimate - estimate);

                    if (!enable) {
                        connectErrorCountUpdater.incrementAndGet(this);

                        if (disableException != null) {
                            throw disableException;
                        }

                        throw new DataSourceDisableException();
                    }
                } catch (InterruptedException ie) {
                    notEmpty.signal(); // propagate to non-interrupted thread
                    notEmptySignalCount++;
                    throw ie;
                } finally {
                    notEmptyWaitThreadCount--;
                }

                if (poolingCount == 0) {
                    if (estimate > 0) {
                        continue;
                    }

                    waitNanosLocal.set(nanos - estimate);
                    return null;
                }
            }

            decrementPoolingCount();
            // 获取连接池中connections的最后一个连接
            DruidConnectionHolder last = connections[poolingCount];
            // 代表connections该位置连接已经被使用了
            connections[poolingCount] = null;

            long waitNanos = nanos - estimate;
            last.setLastNotEmptyWaitNanos(waitNanos);

            return last;
        }
    }

获取连接的时候发现poolCount=0,这个时候会唤醒createThread去创建Connection。创建线程是之前提到的CreateConnectionThread来负责的;先看下这个线程的初始化

private final CountDownLatch initedLatch = new CountDownLatch(2);
// 创建创建连接的守护线程
createAndStartCreatorThread();
// 创建销毁连接的守护线程
createAndStartDestroyThread();

// 等待以上两个守护线程初始化完成后再继续
initedLatch.await();

创建创建连接的守护线程createAndStartCreatorThread,

protected void createAndStartCreatorThread() {
        if (createScheduler == null) {
            String threadName = "Druid-ConnectionPool-Create-" + System.identityHashCode(this);
            // 创建创建连接的线程
            createConnectionThread = new CreateConnectionThread(threadName);
            createConnectionThread.start();
            return;
        }

        initedLatch.countDown();
}

public class CreateConnectionThread extends Thread {

        public CreateConnectionThread(String name){
            super(name);
            // 设置为守护线程
            this.setDaemon(true);
        }

        public void run() {
            initedLatch.countDown();

            long lastDiscardCount = 0;
            int errorCount = 0;
            // 死循环创建连接
            for (;;) {
                // addLast
                try {
                    lock.lockInterruptibly();
                } catch (InterruptedException e2) {
                    break;
                }

                long discardCount = DruidDataSource.this.discardCount;
                boolean discardChanged = discardCount - lastDiscardCount > 0;
                lastDiscardCount = discardCount;

                try {
                    boolean emptyWait = true;

                    if (createError != null
                            && poolingCount == 0
                            && !discardChanged) {
                        emptyWait = false;
                    }

                    if (emptyWait
                            && asyncInit && createCount < initialSize) {
                        emptyWait = false;
                    }

                    if (emptyWait) {
                        // 必须存在线程等待,才创建连接
                        if (poolingCount >= notEmptyWaitThreadCount //
                                && (!(keepAlive && activeCount + poolingCount < minIdle))
                                && !isFailContinuous()
                        ) {
                            // 初始化的时候一直在这里等待
                            empty.await();
                        }

                        // 防止创建超过maxActive数量的连接
                        if (activeCount + poolingCount >= maxActive) {
                            empty.await();
                            continue;
                        }
                    }

                } catch (InterruptedException e) {
                    lastCreateError = e;
                    lastErrorTimeMillis = System.currentTimeMillis();

                    if ((!closing) && (!closed)) {
                        LOG.error("create connection Thread Interrupted, url: " + jdbcUrl, e);
                    }
                    break;
                } finally {
                    lock.unlock();
                }

                PhysicalConnectionInfo connection = null;

                try {
                    // 创建物理连接
                    connection = createPhysicalConnection();
                } catch (SQLException e) {
                    LOG.error("create connection SQLException, url: " + jdbcUrl + ", errorCode " + e.getErrorCode()
                              + ", state " + e.getSQLState(), e);

                    errorCount++;
                    if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) {
                        // fail over retry attempts
                        setFailContinuous(true);
                        if (failFast) {
                            lock.lock();
                            try {
                                notEmpty.signalAll();
                            } finally {
                                lock.unlock();
                            }
                        }

                        if (breakAfterAcquireFailure) {
                            break;
                        }

                        try {
                            Thread.sleep(timeBetweenConnectErrorMillis);
                        } catch (InterruptedException interruptEx) {
                            break;
                        }
                    }
                } catch (RuntimeException e) {
                    LOG.error("create connection RuntimeException", e);
                    setFailContinuous(true);
                    continue;
                } catch (Error e) {
                    LOG.error("create connection Error", e);
                    setFailContinuous(true);
                    break;
                }

                if (connection == null) {
                    continue;
                }

                boolean result = put(connection);
                if (!result) {
                    JdbcUtils.close(connection.getPhysicalConnection());
                    LOG.info("put physical connection to pool failed.");
                }

                errorCount = 0; // reset errorCount

                if (closing || closed) {
                    break;
                }
            }
        }
    }

创建销毁连接的守护线程DestroyConnectionThread

protected void createAndStartDestroyThread() {
        destroyTask = new DestroyTask();

        if (destroyScheduler != null) {
            long period = timeBetweenEvictionRunsMillis;
            if (period <= 0) {
                period = 1000;
            }
            // 目测是使用netty的时间轮算法进行定时执行
            destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destroyTask, period, period,
                                                                          TimeUnit.MILLISECONDS);
            initedLatch.countDown();
            return;
        }

        String threadName = "Druid-ConnectionPool-Destroy-" + System.identityHashCode(this);
        destroyConnectionThread = new DestroyConnectionThread(threadName);
        destroyConnectionThread.start();
    }
public class DestroyConnectionThread extends Thread {

        public DestroyConnectionThread(String name){
            super(name);
            // 守护线程
            this.setDaemon(true);
        }

        public void run() {
            initedLatch.countDown();

            for (;;) {
                // 从前面开始删除
                try {
                    if (closed || closing) {
                        break;
                    }

                    if (timeBetweenEvictionRunsMillis > 0) {
                        Thread.sleep(timeBetweenEvictionRunsMillis);
                    } else {
                        Thread.sleep(1000); //
                    }

                    if (Thread.interrupted()) {
                        break;
                    }

                    destroyTask.run();
                } catch (InterruptedException e) {
                    break;
                }
            }
        }

    }
public class DestroyTask implements Runnable {
        public DestroyTask() {

        }

        @Override
        public void run() {
            shrink(true, keepAlive);

            if (isRemoveAbandoned()) {
                removeAbandoned();
            }
        }

    }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周润发的弟弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值