Druid源码分析系列1:dataSource.init()的准备工作

本文详细解析了阿里巴巴Druid数据源的初始化过程,包括获取锁、检查状态、配置属性验证、驱动类处理等关键步骤,并针对不同数据库类型初始化特定组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本节,讲解

dataSource.init();

打断点在

stop in com.alibaba.druid.pool.DruidDataSource.init

好,开始研究代码

public void init() throws SQLException {
		// 首先确定没有inited
		if (inited) {
			return;
		}
		//继续处理
		//获取lock
		final ReentrantLock lock = this.lock;
		try {
			//尝试获取lock
			lock.lockInterruptibly();
		} catch (InterruptedException e) {
			throw new SQLException("interrupt", e);
		}
		//
		boolean init = false;
		try {
			//再次check没有初始化过,有点类似于double check
			if (inited) {
				return;
			}
			//
			//
			//
			// main[1] print initStackTrace
			// initStackTrace =
			// "java.lang.Thread.getStackTrace(Thread.java:1556)
			// com.alibaba.druid.pool.DruidDataSource.init(DruidDataSource.java:637)
			// com.alibaba.druid.pool.DruidDataSourceFactory.config(DruidDataSourceFactory.java:376)
			// com.alibaba.druid.pool.DruidDataSourceFactory.createDataSource(DruidDataSourceFactory.java:154)
			// com.alibaba.druid.pool.DruidDataSourceFactory.createDataSource(DruidDataSourceFactory.java:144)
			// user.defined.MyDataSourceFactory.getDataSource(MyDataSourceFactory.java:24)
			// org.apache.ibatis.builder.xml.XMLConfigBuilder.environmentsElement(XMLConfigBuilder.java:428)
			// org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:150)
			// org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:111)
			// org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:82)
			// org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:65)
			// test.Test.main(Test.java:23)
			// "
			initStackTrace = Utils.toString(Thread.currentThread().getStackTrace());

继续执行

//获取本数据源的ID标志
			this.id = DruidDriver.createDataSourceId();
			if (this.id > 1) {
				//同1个JVM里可能有多个数据源,就有多个ID
				long delta = (this.id - 1) * 100000;
				this.connectionIdSeed.addAndGet(delta);
				this.statementIdSeed.addAndGet(delta);
				this.resultSetIdSeed.addAndGet(delta);
				this.transactionIdSeed.addAndGet(delta);
			}

然后处理JDBC

// 处理url
			if (this.jdbcUrl != null) {
				this.jdbcUrl = this.jdbcUrl.trim();
				//进去没做什么事情
				initFromWrapDriverUrl();
			}

接下来是插件机制,就是初始化了插件

然后是确定dbType

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

这个是根据url的前缀来做的。

======================================================

//构建connectProperties
			if (JdbcConstants.MYSQL.equals(this.dbType) || //
					JdbcConstants.MARIADB.equals(this.dbType)) {
				//
				boolean cacheServerConfigurationSet = false;
				if (this.connectProperties.containsKey("cacheServerConfiguration")) {
					cacheServerConfigurationSet = true;
				} else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) {
					cacheServerConfigurationSet = true;
				}
				if (cacheServerConfigurationSet) {
					this.connectProperties.put("cacheServerConfiguration", "true");
				}
			}
//简单的参数check
			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);
			}

			if (timeBetweenLogStatsMillis > 0 && useGlobalDataSourceStat) {
				throw new IllegalArgumentException(
						"timeBetweenLogStatsMillis not support useGlobalDataSourceStat=true");
			}

			if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
				throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
			}
// 处理driverClass
			if (this.driverClass != null) {
				this.driverClass = driverClass.trim();
			}
			//
			//
			//
			//什么都不做
			initFromSPIServiceLoader();
//确定driverClass创建实例
			if (this.driver == null) {
				if (this.driverClass == null || this.driverClass.isEmpty()) {
					this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl);
				}

				if (MockDriver.class.getName().equals(driverClass)) {
					driver = MockDriver.instance;
				} else {
					driver = JdbcUtils.createDriver(driverClassLoader, driverClass);
				}
			} else {
				if (this.driverClass == null) {
					this.driverClass = driver.getClass().getName();
				}
			}
Step completed: "thread=main", com.alibaba.druid.pool.DruidDataSource.init(), line=718 bci=649
718    			initCheck();

main[1] step
> 
Step completed: "thread=main", com.alibaba.druid.pool.DruidDataSource.initCheck(), line=942 bci=0
942    		if (JdbcUtils.ORACLE.equals(this.dbType)) {

main[1] next
> 
Step completed: "thread=main", com.alibaba.druid.pool.DruidDataSource.initCheck(), line=955 bci=125
955    		} else if (JdbcUtils.DB2.equals(dbType)) {

main[1] next
> 
Step completed: "thread=main", com.alibaba.druid.pool.DruidDataSource.initCheck(), line=958 bci=142
958    	}

===========接下来,就是initExceptionSorter();   看看,怎么执行的。

private void initExceptionSorter() {
		//从这里开始
		if (exceptionSorter instanceof NullExceptionSorter) {
			if (driver instanceof MockDriver) {
				return;
			}
		} else if (this.exceptionSorter != null) {
			return;
		}

		String realDriverClassName = driver.getClass().getName();
		if (realDriverClassName.equals(JdbcConstants.MYSQL_DRIVER) //
				|| realDriverClassName.equals(JdbcConstants.MYSQL_DRIVER_6)) {
			//处理这个
			this.exceptionSorter = new MySqlExceptionSorter();

---创建ConnectionChecker

private void initValidConnectionChecker() {
		//here
		//
		String realDriverClassName = driver.getClass().getName();
		if (realDriverClassName.equals(JdbcConstants.MYSQL_DRIVER) //
				|| realDriverClassName.equals(JdbcConstants.MYSQL_DRIVER_6)) {
			//针对mysql创建
			this.validConnectionChecker = new MySqlValidConnectionChecker();
		} else if (realDriverClassName.equals(JdbcConstants.ORACLE_DRIVER)
				|| realDriverClassName.equals(JdbcConstants.ORACLE_DRIVER2)) {
			this.validConnectionChecker = new OracleValidConnectionChecker();
		} else if (realDriverClassName.equals(JdbcConstants.SQL_SERVER_DRIVER)
				|| realDriverClassName.equals(JdbcConstants.SQL_SERVER_DRIVER_SQLJDBC4)
				|| realDriverClassName.equals(JdbcConstants.SQL_SERVER_DRIVER_JTDS)) {
			this.validConnectionChecker = new MSSQLValidConnectionChecker();
		} else if (realDriverClassName.equals(JdbcConstants.POSTGRESQL_DRIVER)) {
			this.validConnectionChecker = new PGValidConnectionChecker();
		}
	}
 public MySqlValidConnectionChecker(){
        try {
            clazz = Utils.loadClass("com.mysql.jdbc.MySQLConnection");
            if (clazz == null) {
                clazz = Utils.loadClass("com.mysql.cj.jdbc.ConnectionImpl");
            }

            if (clazz != null) {
                ping = clazz.getMethod("pingInternal", boolean.class, int.class);
            }

            if (ping != null) {
                usePingMethod = true;
            }
        } catch (Exception e) {
            LOG.warn("Cannot resolve com.mysql.jdbc.Connection.ping method.  Will use 'SELECT 1' instead.", e);
        }

        configFromProperties(System.getProperties());
    }

接着初始化QueryChecker

Step completed: "thread=main", com.alibaba.druid.pool.DruidDataSource.validationQueryCheck(), line=912 bci=4
912    		if (!(isTestOnBorrow() || isTestOnReturn() || isTestWhileIdle())) {

main[1] step
> 
Step completed: "thread=main", com.alibaba.druid.pool.DruidDataSource.validationQueryCheck(), line=916 bci=22
916    		if (this.validConnectionChecker != null) {

main[1] print validConnectionChecker
 validConnectionChecker = "com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker@2d1ef81a"
main[1] step
> 
Step completed: "thread=main", com.alibaba.druid.pool.DruidDataSource.validationQueryCheck(), line=917 bci=29
917    			return;

main[1] step

看来不需要创建了。

转载于:https://my.oschina.net/qiangzigege/blog/884024

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值