连接池的基本思想就是为连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立连接时,只需要从缓冲池中取出一个了,使用完毕后再放回去。
apache commons-pool
是apache基金会的一个开源对象池组件,我们常用的数据库连接池dpcp
和redis
的java客户端jedis都使用commons-pool
来管理连接。
主要提供这个几种类型的对象池:
这篇文章主要介绍GenericObjectPool
的实现。
工作原理:
连接池的核心思想是连接的复用,通过建立一个数据库连接池以及一套连接使用、分配和管理策略,使得该连接池中的连接可以得到高效,安全的复用,避免了数据库连接频繁建立和关闭的开销。
连接池的工作原理主要由三部分组成,分别为连接池的建立,连接池中连接的使用管理,连接池的关闭。
连接池的建立。一般在系统初始化时,连接池会根据系统配置建立,并在池中建立几个连接对象,以便使用时能从连接池中获取,连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。
连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其策略是:
当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;如果没有控线连接,则查看当前所开的连接数是否已经达到最大连接数,例如如果没有达到就重新创建一个请求的客户;如果达到,就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。
连接池的关闭。当应用程序退出时,关闭连接池中所有的链接,释放连接池相关资源,该过程正好与创建相反。
源码分析
commons-pool
定义了一个接口PooledObject
来封装池中的对象,添加了空闲时间,使用时间等信息和对象状态流转的行为。
对象池定义
对象池(连接池)是我们保存对象的地方,对象的获取,归还和定时检查都通过对象池来实现。以GenericObjectPool为例,使用了线程安全的集合类来保存对象,LinkedBlockingDeque用于保存空闲的对象,ConcurrentHashMap保存全部对象.
|
|
|
|
获取连接:borrowObject
连接池借出对象时,经过Abandoned
和validate
两种检查,在连接池满时根据配置执行对应的等待策略,当没有可用对象时会抛出异常。
Abandoned
检查目标是连接池所有被借出的对象,主要防止对象借出之后长时间被占用,不能退还(或者使用者忘记return)到连接池导致连接被耗尽。validate
检查目标是当前即将被借出的对象,目的是保证提供的对象是可用的,检查方式由对象工厂的validateObject
方法定义。
|
|
1) 当客户请求数据库连接时,首先查看连接池中是否有空闲连接;
2) 如果存在空闲连接,则将连接分配给客户使用;如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数;
3) 如果没有达到就重新创建一个连接;如果达到最大连接数,就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。
释放连接:returnObject
|
|
1) 从allObjects
中获取要归还的连接
2) 如果idleObjects
空闲队列中连接数已经>=允许的最大空闲连接数或者连接池已经关闭就直接销毁这个连接
3) 否则,将连接放入到idleObjects
队列中, 一旦将连接放入到idleObjects
中如果连接长时间不被使用就会被自动回收(由后台驱逐线程回收空闲连接)
销毁连接
|
|
回收空闲连接:evict
启动驱逐者线程
|
|
|
|
驱逐者Evictor
,在BaseGenericObjectPool
中定义,本质是由java.util.TimerTask
定义的定时任务.
驱逐者线程执行
|
|
驱逐者线程Evictor
被多个连接池共享,但是这些连接池可能属于不同的classloader
,所以Evictor
必须要保证它的所有行为在当前这个连接池的classloader下执行