6 Apache Commons Pool

Wu Jun 2019-01-05 17:03:34
16 辅助工具类 > 1 Apache Commons

Pool项目官网

概览

Apache Commons Pool开源软件库是对象池技术的一种具体实现,提供了一个对象池API和许多对象池实现。简单的说就是将对象一次创建多次使用,解决频繁的创建和销毁对象带来的性能损耗问题。

文档

在线 API 文档:Javadoc (2.5.0 release)

使用

下载:downloads Maven :

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.5.0</version>
</dependency>

整个项目有三个包

介绍
org.apache.commons.pool2 对象池API
org.apache.commons.pool2.impl 对象池API实现。
org.apache.commons.pool2.proxy 对象池代理实现。

原理解析

Common-pool2由三大模块组成
对象池(ObjectPool):一种容器,维护“对象列表”的存取,包含池对象工厂
池对象(PooledObject):是对需要放到池里对象的一个包装类,添加了一些附加的信息
池对象工厂(PooledObjectFactory):创建池对象的工厂类,提供池对象的创建、初始化、销毁和验证等功能
关系

即PooledObjectFactory创建PooledObject,放到ObjectPool里管理

1.对象池

使用对象池的一般步骤:创建一个池对象工厂,将该工厂注入到对象池中,当要取池对象,调用borrowObject,当要归还池对象时,调用returnObject,销毁池对象调用clear(),如果要连池对象工厂也一起销毁,则调用close()。

1.1 默认实现

ObjectPool类族中最主要的两类接口是ObjectPoolKeyedObjectPool,具体的实现里有5种:

KeyedObjectPool基于key操作池对象,不同key的容器不同。 操作方法和ObjectPool的差别是要提供key参数。

用户可以通过继承或者封装默认实现使用线程池,或直接使用默认实现。

1.2 GenericObjectPool

GenericObjectPool实现了ObjectPool接口

public interface ObjectPool<t> {
    //获取对象
    T borrowObject() throws Exception, NoSuchElementException, IllegalStateException;
    //归还对象
    void returnObject(T obj) throws Exception;
    //销毁对象
    void invalidateObject(T obj) throws Exception;
    //创建对象
    void addObject() throws Exception, IllegalStateException, UnsupportedOperationException;
    //获取空闲对象数
    int getNumIdle();
    //获取激活对象数
    int getNumActive();
    //销毁对象
    void clear() throws Exception, UnsupportedOperationException;
    //销毁对象、对象工厂
    void close();
}

构造函数需要传入factory和Config:

GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config)

数据结构: 所有对象allObjects用ConcurrentHashMap存储,空闲对象idleObjects用LinkedBlockingDeque存储。

1.3 GenericObjectPoolConfig

GenericObjectPoolConfig是一个配置类,提供了很多参数来控制对象池的相关属性。
GenericObjectPool就是根据GenericObjectPoolConfig的配置信息,使用PooledObjectFactory来维护对象池。

2.对象工厂接口

**池对象工厂(PooledObjectFactory)是创建和管理池对象(PooledObject)**生命周期的通用接口:

public interface PooledObjectFactory<T> {
    //创建对象
    PooledObject<T> makeObject();
    //激活对象,重新初始化,使对象焕然如新。
    void activateObject(PooledObject<T> obj);
    //钝化对象,让对象置为未初始化状态。
    void passivateObject(PooledObject<T> obj);
    //验证对象
    boolean validateObject(PooledObject<T> obj);
    //销毁对象
    void destroyObject(PooledObject<T> obj);
}

PooledObjectFactory在包里没有具体实现,因为这涉及到具体对象的创建,需要应用本身去实现,这也体现了设计上的解耦合性。

实现PoolableObjectFactory接口的最简单方法是扩展BasePooledObjectFactory抽象类。

和ObjectPool相对应的,PooledObjectFactory也有一个相应的KeyedPooledObjectFactory,他们的区别也一样,一个是基于key来操作一个不是。

3.池对象

PooledObject主要是对需要被加入到pool里的对象提供一个包装,方便来查看或者统计一些对象信息。

PooledObject接口里的基本方法定义

public interface PooledObject<t> extends Comparable<pooledobject<t>> {
    T getObject();
    long getCreateTime();
    long getActiveTimeMillis();
    long getIdleTimeMillis();
    long getLastBorrowTime();
    long getLastReturnTime();
    long getLastUsedTime();
    @Override
    int compareTo(PooledObject<t> other);
    @Override
    boolean equals(Object obj);
    @Override
    int hashCode();
    @Override
    String toString();
    boolean startEvictionTest();
    boolean endEvictionTest(Deque<pooledobject<t>> idleQueue);
    boolean allocate();
    boolean deallocate();
    void invalidate();
    void setLogAbandoned(boolean logAbandoned);
    void use();
    void printStackTrace(PrintWriter writer);
    PooledObjectState getState();
    void markAbandoned();
    void markReturning();
}

类关系图

impl包中提供了PooledObject的默认实现DefaultPooledObject。要使用DefaultPooledObject封装,请使用

@Override
 public PooledObject<Foo> wrap(Foo foo) {
    return new DefaultPooledObject<Foo>(foo);
 }

实例

apache的连接池工具库common-dbcp是基于common-pool实现的,而Jedis的连接池基于commons-pool2实现。

Apache commons-pool2使用的基本步骤:

步骤一: 实现自己的PooledObjectFactory

有时爬虫经常会用到WebDriver,以实现的PooledObjectFactory管理WebDriver为例,其代码如下:

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriver;

/**
 * @author wujun
 * @date 2018-04-19 16:10
 */
public class PooledWebDriverFactory implements PooledObjectFactory<WebDriver> {

    @Override
    public PooledObject<WebDriver> makeObject() throws Exception {
        WebDriver webDriver = new PhantomJSDriver();
        return new DefaultPooledObject<>(webDriver);
    }

    @Override
    public void destroyObject(PooledObject<WebDriver> p) throws Exception {
        WebDriver webDriver = p.getObject();
        if (webDriver != null) {
            webDriver.quit();
        }
    }

    @Override
    public boolean validateObject(PooledObject<WebDriver> p) {
        return p.getObject() != null;
    }

    @Override
    public void activateObject(PooledObject<WebDriver> p) throws Exception {
        if (null == p.getObject()) {
            p = makeObject();
        }
    }

    @Override
    public void passivateObject(PooledObject<WebDriver> p) throws Exception {

    }
}

步骤二: 创建ObjectPool对象

可直接使用GenericObjectPool,若第二个参数GenericObjectPoolConfig不传则会使用默认config。也可继承或者封装GenericObjectPool完成自己的需求。

ObjectPool op = new GenericObjectPool<WebDriver>(new PooledWebDriverFactory());

步骤三: 从ObjectPool获取到PooledObject对象,进行相关业务操作

ObjectPool op = new GenericObjectPool<WebDriver>(new PooledWebDriverFactory());
WebDriver webDriver = (WebDriver) op.borrowObject();
webDriver.get(url);
op.returnObject(webDriver);

参考

Apache commons-pool对象池原理分析
开源项目剖析之apache-common-pool
Apache commons-pool2-2.4.2源码学习笔记
Apache Common-pool2对象池分析和应用
Apache common-pool,common-dbcp源码解读与对象池原理剖析