Day03 DruidDataSource连接池的初始化

前两天发现严重跑偏,发现大家都在梳理druid的pool的关键类,druiddatasource,init流程啊,getconnection里是如何执行的呢。

感觉模模糊糊懂个大概,今天我也来研究下

DruidDataSource连接池的初始化

//线程池初始化,在starter方法或者其他初始化方式
public void init() throws SQLException {
   //已经在初始化就不在进行初始化了。
   if (inited) {
       return;
  }

   //驱动加载,可以看看githug上面的bug说明。
   // bug fixed for dead lock, for issue #2980
   DruidDriver.getInstance();

   final ReentrantLock lock = this.lock;//可重入锁
   try {
       lock.lockInterruptibly(); //获取锁 (优先考虑响应中断,而不是响应锁的普通获取或重入获取)
  } catch (InterruptedException e) {
       throw new SQLException("interrupt", e);
  }

   boolean init = false;
   try {
       if (inited) {
           return;
      }

       //线程栈信息,这个只是记录了,没有看到地方调用,应该是为了给客户端使用的。
       initStackTrace = Utils.toString(Thread.currentThread().getStackTrace());

       //定义了几个原子数据,具体作用未知,每个dataSource都会增加一个
       this.id = DruidDriver.createDataSourceId();
       if (this.id > 1) {
           long delta = (this.id - 1) * 100000;
           //异步创建线程池的时候用到了
           this.connectionIdSeedUpdater.addAndGet(this, delta);
           this.statementIdSeedUpdater.addAndGet(this, delta);
           this.resultSetIdSeedUpdater.addAndGet(this, delta);
           this.transactionIdSeedUpdater.addAndGet(this, delta);
      }

       //spring环境下properties参数在加载DruidDataSourceAutoConfigure的时候加载DataSourceProperties ,DruidStatProperties的时候加载进去的。

       if (this.jdbcUrl != null) {
           this.jdbcUrl = this.jdbcUrl.trim();
           //初始化包装方式的url,比如:jdbc:wrap-jdbc:filters=:name=driverWrapperTest:jdbc:derby:memory:driverWrapperTestDB;create=true
           initFromWrapDriverUrl();
      }

       //为配置的filter初始化
       //这里面主要是做配置的初始化(合并SQL、慢查询相关)
       //如果我们没有做相关配置相当于这里面什么都没做
       for (Filter filter : filters) {
           filter.init(this);
      }

       if (this.dbTypeName == null || this.dbTypeName.length() == 0) {
           this.dbTypeName = JdbcUtils.getDbType(jdbcUrl, null);
      }

       DbType dbType = DbType.of(this.dbTypeName);
       if (dbType == DbType.mysql
               || dbType == DbType.mariadb
               || dbType == DbType.oceanbase
               || dbType == DbType.ads) {
           boolean cacheServerConfigurationSet = false;
           //spring环境下connectProperties由DruidDataSourceAutoConfigure加载完成
           if (this.connectProperties.containsKey("cacheServerConfiguration")) {
               cacheServerConfigurationSet = true;
          } else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) {
               cacheServerConfigurationSet = true;
          }
           if (cacheServerConfigurationSet) {
               this.connectProperties.put("cacheServerConfiguration", "true");
          }
      }

       if (maxActive <= 0) {
           throw new IllegalArgumentException("illegal maxActive " + maxActive);
      }

       if (maxActive < minIdle) {
           throw new IllegalArgumentException("illegal maxActive " + maxActive);
      }

       if (getInitialSize() > maxActive) {
           throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActive " + maxActive);
      }

       //timeBetweenLogStatsMillis 将监控数据发送到文件中的间隔时间
       if (timeBetweenLogStatsMillis > 0 && useGlobalDataSourceStat) {
           throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGlobalDataSourceStat=true");
      }

       if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
           throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
      }

       //keepAlive 是否保活
       //keepAliveBetweenTimeMillis 保活检查间隔时间
       //timeBetweenEvictionRunsMillis 检测需要关闭的空闲连接的间隔时间,单位是毫秒
       if (keepAlive && keepAliveBetweenTimeMillis <= timeBetweenEvictionRunsMillis) {
           throw new SQLException("keepAliveBetweenTimeMillis must be grater than timeBetweenEvictionRunsMillis");
      }

       if (this.driverClass != null) {
           this.driverClass = driverClass.trim();
      }

       //从spi加载filter,会和druid的初始化filters进行去重
       initFromSPIServiceLoader();

       //加载驱动类(里面有四种不同的创建驱动的类加载方式,可以参考下),支持mock类型的驱动名称
       resolveDriver();

       //oracle和db2的连接检查
       initCheck();

       //当数据库抛出一些不可恢复的异常时,抛弃连接
initExceptionSorter();
       //初始化检测数据库连接是否有效的方法 (设置 usePingMethod, 默认是true)
       //1. usePingMethod=true 使用ping方式检测连接有效性 (validationQuery 这个值在true的情况下就没有用了),
       //2. usePingMethod=false, 使用 validationQuery 检测有效性,如果配置select 1 )
       initValidConnectionChecker();
       //检测有无验证连接的参数,仅仅会记录日志,不会报错
       validationQueryCheck();

       //暂不清楚这个作用是什么,druid.globalDbType的功能是什么?
       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 {
           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;

       //判断是否使用异步创建连接
       if (createScheduler != null && asyncInit) {
           for (int i = 0; i < initialSize; ++i) {
               //开启异步创建连接的线程
               submitCreateTask(true);
          }
      } else if (!asyncInit) {
           // init connections
           while (poolingCount < initialSize) {
               try {
                   //创建真正的连接 Connect
                   PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
                   DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
                   connections[poolingCount++] = holder; //生成好的连接直接往后排
              } catch (SQLException ex) {
                   LOG.error("init datasource error, url: " + this.getUrl(), ex);
                   // initExceptionThrow
                   if (initExceptionThrow) {
                       connectError = ex;
                       break;
                  } else {
                       Thread.sleep(3000);
                  }
              }
          }

           if (poolingCount > 0) {
               poolingPeak = poolingCount;
               poolingPeakTime = System.currentTimeMillis();
          }
}

       createAndLogThread();//创建并记录连接池信息到日志
       createAndStartCreatorThread();//开启创建连接的守护线程
       createAndStartDestroyThread();//开启负责丢弃连接的守护线程

       //阻塞上面线程的执行,在createAndStartCreatorThread 和 createAndStartDestroyThread 分别调用了 initedLatch.countDown(),计数器正好为0
       initedLatch.await();
       init = true;
initedTime = new Date();
       registerMbean();//把dataSource加入到stat中

       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();
          }
      }

  } catch (SQLException e) {
       LOG.error("{dataSource-" + this.getID() + "} init error", e);
       throw e;
  } catch (InterruptedException e) {
       throw new SQLException(e.getMessage(), e);
  } catch (RuntimeException e){
       LOG.error("{dataSource-" + this.getID() + "} init error", e);
       throw e;
  } catch (Error e){
       LOG.error("{dataSource-" + this.getID() + "} init error", e);
       throw 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);
      }
  }
}

再看下流程图消化一下

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值