Druid连接池源码解析(1)

 一直想研究下Druid连接池底层的源码实现,正好今天有空,废话不说直接上源码。

 今天先上最核心的连接池部分,至于后续的源码,后面会逐步安排上。

 

首先我们先来到源码的入口,我这里选用了test包中的,一个测试类。不得不说作者提供的测试类,还是挺多的。

        

通过上面的获取getConnection方法,可以直接进入DruidDataSource核心的init方法

init 方法上来:

  (1)先初始化DruidDriver,在DruidDriver类被加载时,会进行了比较重要的两件事

//1.注册driveManager
DriverManager.registerDriver(driver);
//把driver注册到jmx上
mbeanServer.registerMBean(instance, objectName);

注册到jmx上就可以通过java提供的监控工具,在程序运行的时候,动态的监控,内部的属性值了,  也可以通过手动点击的方法,调用下列方法    监控的属性如下: 

//JMX可以监控版本
String getDruidVersion();

//JMX中可以监控Druid的连接数
long getConnectCount();

//可以在JMX中手动调用 resetStat方法
void resetStat();

String getAcceptPrefix();

boolean jdbcCompliant();

int getMinorVersion();

int getMajorVersion();

//
String[] getDataSourceUrls();

(2) 可以通过调整url连接的样式,完成过滤器的注入操作.配置的样式如下:

  jdbc:wrap-jdbc:driver=rawClassName:filters= , :name=:     jmx=true/false

 其中:rawClassName  为驱动对应的className的类名。可以手动指定使用哪种驱动类.

 filters= 后面就是配置过滤器参数的,多个参数用逗号隔开.

 name表示数据源的名称

 jmx:表示jdbcstat数据是否要监控

(3)如果外部配置了filter列表,在这个块会被初始化。通过这可以看出,可以在外部灵活的注入filters参数。

 (4)initFromSPIServiceLoader: 该方法作用是提供了更灵活的方法来配置filter列表,允许通过SPI的机制,在META-INF的service文件夹下,配置filter列表,这边提供了一个关闭已配置的filter的功能,通过在Filter类上配置AutoLoad(value=false)的方式

(5)resolveDriver():应该叫createDrive,就是根据前几步得到,DriveClass类创建驱动.这里面还有对 其他的情况的适配

if (MockDriver.class.getName().equals(driverClass)) {
    driver = MockDriver.instance;
} else if ("com.alibaba.druid.support.clickhouse.BalancedClickhouseDriver".equals(driverClass)) {
    Properties info = new Properties();
    info.put("user", username);
    info.put("password", password);
    info.putAll(connectProperties);
    driver = new BalancedClickhouseDriver(jdbcUrl, info);
}

(6)initcheck():确认当前的数据库的类型是mysql,oracle哪种类型

(7) initexceptionsort:里面封装了剔除无用连接的逻辑.就是通过这个类来判断哪些连接是无用的.该方法的作用是,根据数据库使用的类型,判断使用哪一种剔除器

(8)initValidConnectionChecker:初始化维护连接器,要想维护长连接,必须给mysql发送心跳包.通过MySqlValidConnectionChecker 这个类中的isValidConnection方法,类维护连接的有效性.

//判断是否使用全部的状态监控
if (isUseGlobalDataSourceStat()) {
                dataSourceStat = JdbcDataSourceStat.getGlobal();
                if (dataSourceStat == null) {
                    dataSourceStat = new JdbcDataSourceStat("Global", "Global", this.dbTypeName);
                    JdbcDataSourceStat.setGlobal(dataSourceStat);
                }
                if (dataSourceStat.getDbType() == null) {
                    dataSourceStat.setDbType(this.dbTypeName);
                }
            } else {   
                //初始化JdbcDataSourceStat类,用来统计JdbcSqlStat的参数
                dataSourceStat = new JdbcDataSourceStat(this.name, this.jdbcUrl, this.dbTypeName, this.connectProperties);
            }
            dataSourceStat.setResetStatEnable(this.resetStatEnable);

            connections = new DruidConnectionHolder[maxActive];
            evictConnections = new DruidConnectionHolder[maxActive];
            keepAliveConnections = new DruidConnectionHolder[maxActive];

            SQLException connectError = null;

            //下面是对连接的初始化操作,提供了两个方式
        (1).异步初始化操作
            if (createScheduler != null && asyncInit) {
                for (int i = 0; i < initialSize; ++i) {
                    submitCreateTask(true);
                }
            } else if (!asyncInit) {
             (2)同步初始化操作
                // init connections
                while (poolingCount < initialSize) {
                    try {
                //创建连接或者代理的连接.并且统计连接的各种时间
                        PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
                //用一个Holder类来包装连接
                        DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
                //把holder放入到连接池中
                        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();
                }
            }
PhysicalConnectionInfo类中包含的属性
//物理连接,这个连接有可能是代理连接
private Connection connection;
//连接开始的时间
private long connectStartNanos;
//建立连接的时候
private long connectedNanos;
//初始化参数的时间
private long initedNanos;
//校验完成的时间
private long validatedNanos;
//该库对应的参数
private Map<String, Object> vairiables;
//全局对应的参数
private Map<String, Object> globalVairiables;
           //后台创建线程 间隔一段时间,打印日志信息
      createAndLogThread();
         
            //当连接过多时,就停止创建,阻塞该线程
            createAndStartCreatorThread();
            
            //当连接小于minIdle的时候,就唤醒上的线程,创建连接
            createAndStartDestroyThread();

            initedLatch.await();
            init = true;

            initedTime = new Date();
            registerMbean();

            if (connectError != null && poolingCount == 0) {
                throw connectError;
            }

            if (keepAlive) {
                // async fill to minIdle
                if (createScheduler != null) {
                    for (int i = 0; i < minIdle; ++i) {
                        submitCreateTask(true);
                    }
                } else {
                    this.emptySignal();
                }
            }
 
 

2

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值