Druid源码主流程分析

版本

Druid: 1.2.5

主流程分析

作为一个数据库连接池,核心功能就是池化连接,而作为使用者,用户从池子中申请连接,完成数据库操作,不用去关心申请连接,销毁连接,池化连接的具体细节。

JDK的javax.sql包的DataSource接口定义了数据源的核心操作

  Connection getConnection() throws SQLException;
  Connection getConnection(String username, String password) throws SQLException;

Druid的源码中使用了JUC包中的同步组件

使用了ReentrantLock以及Condition来同步协调,用户线程,创建连接线程,销毁连接线程的协作

核心基本集中在DruidDataSource类中,比较重要的四个过程

  • 初始化数据库连接池:init方法
  • 用户线程获取连接:DruidPooledConnection getConnection()
  • 创建连接线程:CreateConnectionThread
  • 清理连接线程:DestroyConnectionThread

DruidDataSource继承自DruidAbstractDataSource,DruidAbstractDataSource的构造方法指定了传入锁的类型,并且创建了两个condition

    public DruidAbstractDataSource(boolean lockFair){
        lock = new ReentrantLock(lockFair);
        // 用于用户线程阻塞等待,通知用户线程有可用连接
        notEmpty = lock.newCondition();
        // 用于创建连接线程阻塞等待,通知创建连接线程创建
        empty = lock.newCondition();
    }

一张简图大概梳理了关系
在这里插入图片描述

初始化过程

public void init() throws SQLException {
        if (inited) {
            return;
        }
        // bug fixed for dead lock, for issue #2980
        DruidDriver.getInstance();
        final ReentrantLock lock = this.lock;
        try {
            // lock是个可重入锁,加锁
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            throw new SQLException("interrupt", e);
        }
        boolean init = false;
        try {
            // 如果初始化过了,直接返回
            if (inited) {
                return;
            }
		   // filters初始化
            for (Filter filter : filters) {
                filter.init(this);
            }
		   // load filters from SPI ServiceLoader
            initFromSPIServiceLoader();
            // 处理driver,实例化driver
            resolveDriver();
		   // 做一些检查
            initCheck();
		   // 初始化exceptionSorter
            initExceptionSorter();
            // ValidConnectionChecker
            initValidConnectionChecker();
            // 做validationQuery检查
            validationQueryCheck();
		   // 持有连接的数组
            connections = new DruidConnectionHolder[maxActive];
            // 要清除的连接
            evictConnections = new DruidConnectionHolder[maxActive];
            // 保活的连接
            keepAliveConnections = new DruidConnectionHolder[maxActive];
            SQLException connectError = null;
            if (createScheduler != null && asyncInit) {
                for (int i = 0; i < initialSize; ++i) {
                    submitCreateTask(true);
                }
            } else if (!asyncInit) {
                // init connections,先创建initialSize个连接
                while (poolingCount < initialSize) {
                    try {
                        PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
                        DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
                        connections[poolingCount++] = holder;
                    } catch (SQLException ex) {
                        LOG.error("init datasource error, url: " + this.getUrl(), ex);
                        if (initExceptionThrow) {
                            connectError = ex;
                            break;
                        } else {
                            Thread.sleep(3000);
                        }
                    }
                }
                if (poolingCount > 0) {
                    poolingPeak = poolingCount;
                    poolingPeakTime = System.currentTimeMillis();
                }
            }
		    // 创建写日志线程并启动,线程前缀:Druid-ConnectionPool-Log-
            createAndLogThread();
            // 创建连接线程 线程前缀:Druid-ConnectionPool-Create-
            createAndStartCreatorThread();
            // 销毁连接线程 定时触发或者Druid-ConnectionPool-Destroy-
            createAndStartDestroyThread();
            /** 等待 创建连接线程 和 销毁连接线程 全部开启才算初始化完成 */
            initedLatch.await();
            if (keepAlive) {
                // async fill to minIdle
                if (createScheduler != null) {
                    for (int i = 0; i < minIdle; ++i) {
                        submitCreateTask(true);
                    }
                } else {
                    this.emptySignal();
                }
            }
        } catch (SQLException e) {
         	...
        } finally {
            // 设置标志
            inited = true;
            // 释放锁
            lock.unlock();
            if (init && LOG.isInfoEnabled()) {
                String msg = "{dataSource-" + this.getID();
                if (this.name != null && !this.name.isEmpty()) {
                    msg += ",";
                    msg += this.name;
                }
                msg += "} inited";
		       // 记录日志
                LOG.info(msg);
            }
        }
    }

获取连接过程

    public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
        // 先尝试初始化,如果初始化过了就返回
        init();
	    // 如果有filter,应用filter链条,最后调用getConnectionDirect
        if (filters.size() > 0) {
            FilterChainImpl filterChain = new FilterChainImpl(this);
            return filterChain.dataSource_connect(this, maxWaitMillis);
        } else {
            return getConnectionDirect(maxWaitMillis);
        }
    }

创建连接线程

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();	// 等待创建连接线程通知
                        }
                        // 激活的+池中的不能比max大
                        // 防止创建超过maxActive数量的连接
                        if (activeCount + poolingCount >= maxActive) {
                            empty.await(); // 等待创建连接线程通知
                            continue;
                        }
                    }

                } catch (InterruptedException e) {
                    lastCreateError = e;
                    lastErrorTimeMillis = System.currentTimeMillis();
                    if (!closing) {
                        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();
                            }
                        }
                        // 这里如果配置了true就会退出for
                        if (breakAfterAcquireFailure) {
                            break;
                        }
                        try {
                            // 睡timeBetweenConnectErrorMillis
                            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;
                }
            }
        }
    }

清理连接线程

 public void run() {
            initedLatch.countDown();
            for (;;) {
                // 从前面开始删除
                try {
                    if (closed) {
                        break;
                    }
                    if (timeBetweenEvictionRunsMillis > 0) {
                        Thread.sleep(timeBetweenEvictionRunsMillis);
                    } else {
                        Thread.sleep(1000); //
                    }
                    if (Thread.interrupted()) {
                        break;
                    }
                    // 调shrink
                    destroyTask.run();
                } catch (InterruptedException e) {
                    break;
                }
            }
        }

具体逻辑在shrink方法

  • 销毁空闲连接

    • 当一个连接长时间没有被使用,如果不及时清理就会造成资源浪费,所以需要定时检查空闲时间过长的连接进行断开连接销毁
  • 回收超时连接

    • 当一个连接被一个线程长时间占有没有被归还,有可能是程序出故障了或是有漏洞导致没有归还连接,这样就可能会导致连接池中的连接不够用,所以需要定时检查占用连接时间过长的线程,如果超过规定时间没有归还连接,则强制回收该连接。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值