common-pools源码分析

  1. 云栖社区>
  2. 博客>
  3. 正文

common-pools源码分析

愤怒的苹果 2016-03-30 16:41:49 浏览2515
展开阅读全文

背景

  前段时间研究了下dbcp的一些源码,发现dbcp对common pools依赖比较严重,基本就是基于pool的扩展接口实现的。所以也就顺便看了下pools的源码。

 

总体结构

 

common pools的代码总体结构来说是比较简单的。

 

先上一个类图:


 

 

核心接口类:

  • ObjectPool             对象池
  • ObjectPoolFactory   池的维护工厂
  • PoolableObjectFactory   可池化对象的维护工厂
  • KeyedObjectPool    基于kety的对象池
  • KeyedObjectPoolFactory
  • KeyedPoolableObjectFactory

说明: ObjectPool和KeyedObjectPool基本接口都是一致的,唯一不同的就是KeyedObjectPool是基于key做为键值,其对应的存储结构就是 Map<Object , List<Object>>, 每次根据key定位List<objct>的value后,再进行池化管理。

几个pools的实现类:

1.  GenericObjectPool: 通用的对象池处理类,维护池的大小,空闲链接等等。 针对对象的makeObject,destoryObject等都是委托给PoolableObjectFactory进行处理。

基本参数和dbcp的配置参数一样,可以参考: http://agapple.iteye.com/admin/blogs/772507

关注几个特别的参数:

  • _lifo :  采用的列表管理模式,采用先进先出or后进先出。 默认是先进先出,底层具体的池对象储存是通过CursorableLinkedList。
  • _softMinEvictableIdleTimeMillis : 软性idle空闲管理。默认是-1。 相比于_minEvictableIdleTimeMillis,系统默认优先处理_minEvictableIdleTimeMillis空闲管理机制,除此主要的区别就是处理空闲链接时,soft会考虑当前的池大小是否满足 > minIdle数。
  • _timeBetweenEvictionRunsMillis :  Evict管理线程的运行时间,默认-1。也就是说默认不运行,注意如果要使用idle空闲管理必须设置该值,否则没效果。

2.  StackObjectPool :  基于stack堆栈概念的对象池,对象池的borrow或者return都是符合stack的先进先出弹栈的管理,相比于GenericObjectPool,它只有maxIdle(最大空闲数), maxTotal(最大资源数)管理,暂时还未想到特定的应用场景,因为觉得GenericObjectPool的功能基本可以覆盖StackObjectPool,只要适当的调整参数。

 

3.  SoftReferenceObjectPool :  看名字就应该猜到是基于SoftReference进行对象持有的pool,在内存不足时可以主动的释放pool object对象, 通过ReferenceQueue获取object对象需要被清除的时间点。至于SoftReference可以看下理解 Java 的 GC 与 幽灵引用

 

4.  GenericKeyedObjectPool: 区别于GenericObjectPool,主要是该pool池,针对每个资源都有自己特定的域,就是一个对应的key。每个key下可以有一组object。 maxTotal是针对所有的key下的object之和,而非单个。

 

如何实现自定义的pool

 

首先以dbcp为例,介绍其相关扩展点。

 

 

 

说明:

1. dbcp整个连接池的管理是使用GenericObjectPool

2. dbcp这里通过扩展实现自定义的PoolableObjectFactory , 用于定义如何创建/销毁/校验一个datasource等。

3. 使用的statement cache利用的是GenericKeyedObjectPool,因为statement cache是基于key进行statement管理的,所以比较适合。但目前在使用statement cache会出现一些异常情况,慎用。

4. PoolingConnection实现了statement cache对应池对象的创建/销毁。 同时在datasource的执行close,同时需要清理整个statement cache pool的close动作,避免出现资源泄漏。

 

 

实际demo: 

实现一个memcache client的连接池代码

 

1. 实现一个PoolableObjectFactory接口,提供创建/销毁/校验的方法


1.   
2.public class MemcachedPoolableSocketFactory implements PoolableObjectFactory {  
3.  .......  
4.  public MemcachedPoolableSocketFactory(String host, int port, int connectedTimeout){  
5.        this.host = host;  
6.        this.port = port;  
7.        this.connectedTimeout = connectedTimeout;  
8.    }  
9.  
10.    @Override  
11.    public Object makeObject() throws Exception {  
12.        return new SockIO(host, port, connectedTimeout);  
13.    }  
14.  
15.    @Override  
16.    public void destroyObject(Object obj) throws Exception {  
17.        if (obj instanceof SockIO) {  
18.            ((SockIO) obj).close();  
19.        }  
20.    }  
21.  
22.    @Override  
23.    public boolean validateObject(Object obj) {  
24.        if (obj instanceof SockIO) {  
25.            SockIO sock = (SockIO) obj;  
26.            try {  
27.                sock.getOut().write("version \r\n".getBytes());  
28.                sock.getOut().flush();  
29.            } catch (IOException e) {  
30.                e.printStackTrace();  
31.            }  
32.        }  
33.        return true;  
34.    }  
35.    ......  
36.  
37.}  

2.  创建SocketPool类,用于管理pool


1.public class MemcachedSocketPool {  
2.  
3.    private GenericObjectPool sockPool  = null;  
4.    private int               maxActive = 50;  
5.    private int               minIdle   = 1;  
6.    private int               maxIdle   = 50;  
7.    private int               maxWait   = 1000;  
8.  
9.    public MemcachedSocketPool(String host, int port){  
10.        sockPool = new GenericObjectPool();  
11.        sockPool.setMaxActive(maxActive);  
12.        sockPool.setMaxIdle(maxIdle);  
13.        sockPool.setMinIdle(minIdle);  
14.        sockPool.setMaxWait(maxWait);  
15.        sockPool.setTestOnBorrow(false);  
16.        sockPool.setTestOnReturn(false);  
17.        sockPool.setTimeBetweenEvictionRunsMillis(10 * 1000);  
18.        sockPool.setNumTestsPerEvictionRun(maxActive + maxIdle);  
19.        sockPool.setMinEvictableIdleTimeMillis(30 * 60 * 1000);  
20.        sockPool.setTestWhileIdle(true);  
21.        sockPool.setFactory(new MemcachedPoolableSocketFactory(host, port, 1000));  
22.    }  
23.  
24.    public SockIO createSocket() {  
25.        assert sockPool != null;  
26.  
27.        try {  
28.            return (SockIO) sockPool.borrowObject();  
29.        } catch (Exception e) {  
30.        }  
31.  
32.        return null;  
33.    }  
34.}  

3. 客户端端使用 


1.MemcachedSocketPool pool = new MemcachedSocketPool("10.20.156.37", 6000);  
2.SockIO sock = pool.createSocket();  
3.sock.write(cmd.getBytes());  
4.sock.flush();  

使用common-pools后,实现一个自己的连接池也是相对比较单了


网友评论

登录后评论
0/500
评论
愤怒的苹果
+ 关注