接上次分享了日志组件后,我们这次来分享一个比较重要mybatis基础组件---数据源组件。提到数据源组件,我想问一个问题:请问从mybatis连接池获取一个数据库连接的过程是怎样的?你知道吗?这好像是BAT大厂的一道面试题吧。别着急我们慢慢来聊。

整体设计架构

mybatis源码解析 - 核心基础组件之数据源组件_第1张图片

今天来分享一下数据源组件的源码实现细节

工厂模式的设计思路

mybatis源码解析 - 核心基础组件之数据源组件_第2张图片

DataSourceFactory: 工厂模式的核心接口,调用者直接和工厂接口交互,用于获取具体的工厂实现类;

DataSource: java数据源的核心接口,用于抽象数据源行为;

UnpooledDataSourceFactory: 非池化工厂的具体实现类,用于创建非池化的数据源对象;

UnpooledDataSource:  主要用于构建原生的Connection对象;

PooledDataSourceFactory: 池化工厂的具体实现类,其继承UnpooledDataSourceFactory非池化工厂类的行为;主要职责创建池化的数据源对象;

PooledDataSource: 池化的数据源,它依赖UnpooledDataSource非池化数据源中连接等信息创建同步、线程安全的池化的数据源。

PooledConnection:  使用动态代理封装和增强原生的Connection数据库连接对象;

PoolState: 用于管理PooledConnection状态的组件,通过维护两个list分别管理空闲和活动的连接资源;

带着如下问题解读mybatis数据源组件设计实现源码

  1. 数据源组件为什么采用工厂模式实现 ?

  2. 池化数据源和非池化数据源有什么联系和区别,池化数据源需要考虑哪些问题?

数据源工厂源码实现

mybatis源码解析 - 核心基础组件之数据源组件_第3张图片

非池化数据源源码实现

mybatis源码解析 - 核心基础组件之数据源组件_第4张图片

池化数据源源码实现

mybatis源码解析 - 核心基础组件之数据源组件_第5张图片

从组件以上的设计思路和源码实现上,我们不难得出以下认知:

1. mybatis自身除了实现内置的数据源外,还要对三方数据源(如:durid, dbcp, c3p0等)的接入提供支持。这种业务设计需求下必须对数据源创建和管理,单独提供入口,并且能方便的切换和适配。

2. 采用常规创建对象的方式, 包括:直接new具体数据源类创建对象和通过反射机制创建对象等方式,很明显有以下缺陷:

缺陷一:对象的创建和使用的职责耦合在一起, 违反了单一职责原则;

缺陷二:当业务扩展时,必须要修改代码,违反了开闭原则;

那么我认为至少基于以上两大原则,mybatis才会考虑使用工厂模式。那工厂模式的明显优点有哪些呢?

1. 把对象的创建和使用的过程分开,这样就达到了把两者的职责分离的目的;

2. 如果创建对象过程比较复杂,创建过程统一放到工厂维护,即减少了重复代码,又方便了以后对相关过程代码的修改;

3. 当业务扩展时,只需要增加工厂子类,符合开闭原则;

OK, 这个问题解决了。那接下来我们将重点分析连接池化技术的设计实现源码。

池化数据源构建

封装池化、增强的数据库连接

mybatis源码解析 - 核心基础组件之数据源组件_第6张图片

封装对池化连接进行管理的核心数据结构

mybatis源码解析 - 核心基础组件之数据源组件_第7张图片mybatis源码解析 - 核心基础组件之数据源组件_第8张图片

idleConnections:空闲池化连接集合, 当连接使用完关闭时,会把它放进这个空闲连接集合缓存; 当获取连接成功时,会将它从该集合中移除。

activeConnections:  正在使用的连接集合,当连接获取成功时,会把池化连接对象放入此集合;当连接关闭时,会把它从该集合中移除。

这两个list集合最终贯穿连接生命周期的始终。

池化数据源管理

拿连接的核心设计思路

mybatis源码解析 - 核心基础组件之数据源组件_第9张图片

拿连接方式和流程总结

mybatis源码解析 - 核心基础组件之数据源组件_第10张图片

上面正好也回答了文章一开始提出的问题!!

close连接的设计思路

mybatis源码解析 - 核心基础组件之数据源组件_第11张图片

关闭连接方式总结

mybatis源码解析 - 核心基础组件之数据源组件_第12张图片


总结

mybatis数据源组件其实设计很精妙,这种设计思路大家值得多思考和在我们的项目中借鉴,尤其是池化技术、设计模式!后面还为分享mybatis一些优秀的组件和设计思想,请继续关注!