写点什么

druid 源码学习三 - 继续探究 DruidDataSource 类 init 方法

作者:Nick
  • 2022 年 5 月 13 日
  • 本文字数:2777 字

    阅读完需:约 9 分钟

druid源码学习三-继续探究DruidDataSource类init方法

继续探究 DruidDataSource 核心类 init 初始化方法

类 DruidDataSource 第 810 行

    lock.lockInterruptibly();
复制代码

ReentrantLock 锁有几种:lock、tryLock、tryLock(long timeout, TimeUnit unit)、lockInterruptibly。


这里简单说下 lock 和 lockInterruptibly 的区别


lock 阻塞等待获取锁,优先考虑获取锁,待获取锁成功后,才响应中断。


lockInterruptibly 优先考虑响应中断,而不是响应锁的普通获取或重入获取。


ReentrantLock.lockInterruptibly 允许在等待时由其它线程调用等待线程的 Thread.interrupt 方法来中断等待线程的等待而直接返回,这时不用获取锁,而会抛出一个 InterruptedException。 ReentrantLock.lock 方法不允许 Thread.interrupt 中断,即使检测到 Thread.isInterrupted,一样会继续尝试获取锁,失败则继续休眠。只是在最后获取锁成功后再把当前线程置为 interrupted 状态,然后再中断线程。


接下来


    initStackTrace = Utils.toString(Thread.currentThread().getStackTrace());//获取当前线程堆栈跟踪元素数组再转换为String
复制代码


线程类的 getStackTrace() 方法返回一个堆栈跟踪元素数组,表示线程的堆栈转储。数组的第一个元素表示堆栈的顶部,它是序列中的最后一个方法调用。数组的最后一个元素表示堆栈的底部,这是序列中的第一个方法调用。


Utils 是 druid 工具类这里定义另一个 toString 方法将 StackTraceElement[]数组转成字符串,如下:


    public static String toString(StackTraceElement[] stackTrace) {        StringBuilder buf = new StringBuilder();        for (StackTraceElement item : stackTrace) {            buf.append(item.toString());            buf.append("\n");        }        return buf.toString();    }
复制代码


        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);        }
复制代码


connectionIdSeedUpdater、statementIdSeedUpdater、resultSetIdSeedUpdater、transactionIdSeedUpdater


这几个都是在抽象类 DruidAbstractDataSource 定义的 AtomicLongFieldUpdater<DruidAbstractDataSource>AtomicLongFieldUpdater 可以对指定"类的 'volatile long'类型的成员"进行原子更新。它是基于反射原理实现的


    public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,                                                           String fieldName) {        Class<?> caller = Reflection.getCallerClass();        if (AtomicLong.VM_SUPPORTS_LONG_CAS)            return new CASUpdater<U>(tclass, fieldName, caller);        else            return new LockedUpdater<U>(tclass, fieldName, caller);    }
复制代码


说明:newUpdater()的作用是获取一个 AtomicIntegerFieldUpdater 类型的对象。它实际上返回的是 CASUpdater 对象,或者 LockedUpdater 对象;具体返回哪一个类取决于 JVM 是否支持 long 类型的 CAS 函数。这里是获取数据库操作相关(connection、statement、resultSet、transction)的种子 ID,并追加了 delta.


    if (this.jdbcUrl != null) {        this.jdbcUrl = this.jdbcUrl.trim();        initFromWrapDriverUrl();    }
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 (JdbcUtils.isMysqlDbType(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"); } }
复制代码


这段初始化了 jdbcUrl 并且获取数据库类型名称 DbType 是个枚举类,定义了市场上几乎所有的数据库名其中 JdbcUtils 类会发现这段代码


    static {        try {            ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader();            if (ctxClassLoader != null) {                for (Enumeration<URL> e = ctxClassLoader.getResources("META-INF/druid-driver.properties"); e.hasMoreElements();) {                    URL url = e.nextElement();
Properties property = new Properties();
InputStream is = null; try { is = url.openStream(); property.load(is); } finally { JdbcUtils.close(is); }
DRIVER_URL_MAPPING.putAll(property); } } } catch (Exception e) { LOG.error("load druid-driver.properties error", e); } }
复制代码


可见驱动都在该属性文件中 druid-driver.properties 打开看果然


jdbc:derby:=org.apache.derby.jdbc.EmbeddedDriver   jdbc:mysql:=com.mysql.jdbc.Driverjdbc:log4jdbc:=net.sf.log4jdbc.DriverSpyjdbc:oracle:=oracle.jdbc.driver.OracleDriverjdbc:microsoft:=com.microsoft.jdbc.sqlserver.SQLServerDriver   jdbc:jtds:=net.sourceforge.jtds.jdbc.Driver   jdbc:postgresql:=org.postgresql.Driver   jdbc:fake:=com.alibaba.druid.mock.MockDriver   jdbc:hsqldb:=org.hsqldb.jdbcDriver   jdbc:db2:=COM.ibm.db2.jdbc.app.DB2Driverjdbc:sqlite:=org.sqlite.JDBC   jdbc:ingres:=com.ingres.jdbc.IngresDriver   jdbc:h2:=org.h2.Driver   jdbc:mckoi:=com.mckoi.JDBCDriverjdbc:clickhouse:=ru.yandex.clickhouse.ClickHouseDriverjdbc:highgo:=com.highgo.jdbc.Driver
复制代码


参考:

https://blog.csdn.net/u013308490/article/details/83062433

https://blog.csdn.net/Shujie_L/article/details/123777561

https://blog.csdn.net/wangxiaotongfan/article/details/51798969

发布于: 刚刚阅读数: 3
用户头像

Nick

关注

终身学习,向死而生 2020.03.18 加入

得到、极客时间重度学习者,来infoQ 是为了输出倒逼输入

评论

发布
暂无评论
druid源码学习三-继续探究DruidDataSource类init方法_Apache Druid_Nick_InfoQ写作社区