apache-common-pool2源码分析

基础概念

apache-common-pool2是一个对象池管理框架,任何需要对象池这种概念的都可以利用这个框架来实现,例如redis的客户端jedis和dbcp都是基于common-pool2实现的。本文是common-pool2的源码分析,在讲源码前我先阐述一下基本对象池的基本概念吧。

现在java创建一个对象的速度已经很快了,但是对于网络连接的创建还是需要很长的时间的,频繁的创建客户端与服务的连接会为系统带来大量的开销。因此,为连接建立缓存机制,就产生了我们现在系统中各种常用的连接池。像各种数据库连接池,服务连接池等。

下面我们就根据common-pool2的源码对对象池的关键环节进行解析。该对象池主要部门就是获取池中对象,将对象归还给池,空闲对象的管理以及对象的销毁这几个环节。

源码解析

0.被池管理的‘对象’下文统一用对象来简称
1.Pool.java 抽象类,

用于使用pool2的实现放池具体实现继承的累
初始化池。获取池中对象方法:getResource();将对象归池中:returnResource()。这只是入口,具体的实现后文详细说明。

2.GenericObjectPool ‘对象’的管理者

2.1 borrowObject() ‘对象’获取规则

规则详述:   
while (p == null) {
        create = false;
        if (blockWhenExhausted) {//获取新‘对象’阻塞
            p = idleObjects.pollFirst();//从空闲队列获取
            if (p == null) {//没有可用的空闲队列
                p = create();//真实创建,下文再叙
                if (p != null) {
                    create = true;
                }
            }
            if (p == null) {//没有从空闲队列获取也没有创建成功(后文会说明why)
                if (borrowMaxWaitMillis < 0) {//等待时间为-1表示一直等待存在空闲
                    p = idleObjects.takeFirst();
                } else {//加入等待时间,到时间没获取返回null
                    p = idleObjects.pollFirst(borrowMaxWaitMillis,
                            TimeUnit.MILLISECONDS);
                }
            }
            if (p == null) {
                throw new NoSuchElementException(
                        "Timeout waiting for idle object");
            }
            if (!p.allocate()) {//对象相应状态标记修改
                p = null;
            }
        } else {//不阻塞
            p = idleObjects.pollFirst();//获取空闲队列中的对象
            if (p == null) {
                p = create();
                if (p != null) {
                    create = true;
                }
            }
            if (p == null) {
                throw new NoSuchElementException("Pool exhausted");
            }
            if (!p.allocate()) {
                p = null;
            }
        }

        if (p != null) {
            try {
                factory.activateObject(p);//初始化该对象
            } catch (Exception e) {
                try {
                    destroy(p);
                } catch (Exception e1) {
                    // Ignore - activation failure is more important
                }
                p = null;
                if (create) {
                    NoSuchElementException nsee = new NoSuchElementException(
                            "Unable to activate object");
                    nsee.initCause(e);
                    throw nsee;
                }
            }
            if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {//getTest***都是配置对象中的值
                boolean validate = false;
                Throwable validationThrowable = null;
                try {
                    validate = factory.validateObject(p);//检查该对象的有效性,校验规则交由实现方
                } catch (Throwable t) {
                    PoolUtils.checkRethrow(t);
                    validationThrowable = t;
                }
                if (!validate) {
                    try {
                        destroy(p);//检验后发现不是合法的对象,直接销毁
                        destroyedByBorrowValidationCount.incrementAndGet();
                    } catch (Exception e) {
                        // Ignore - validation failure is more important
                    }
                    p = null;
                    if (create) {
                        NoSuchElementException nsee = new NoSuchElementException(
                                "Unable to validate object");
                        nsee.initCause(validationThrowable);
                        throw nsee;
                    }
                }
            }
        }
    }

对象真正创建规则

private PooledObject<T> create() throws Exception {
    int localMaxTotal = getMaxTotal();//获取实现方设置的最大对象存在数量
    long newCreateCount = createCount.incrementAndGet();
    if (localMaxTotal > -1 && newCreateCount > localMaxTotal ||
            newCreateCount > Integer.MAX_VALUE) {//大于设置的最大数量直接return null
        createCount.decrementAndGet();
        return null;
    }

    final PooledObject<T> p;
    try {
        p = factory.makeObject();//真正Nnew 对象的地方,交由实现方自己编写
    } catch (Exception e) {
        createCount.decrementAndGet();
        throw e;
    }

    AbandonedConfig ac = this.abandonedConfig;
    if (ac != null && ac.getLogAbandoned()) {
        p.setLogAbandoned(true);
    }

    createdCount.incrementAndGet();//创建对象数量计数
    allObjects.put(new IdentityWrapper<T>(p.getObject()), p);//放入对象缓存,以后在取就直接获取,不用再创建
    return p;
}

2.2对象归还池 returnObject()

 public void returnObject(T obj) {

    PooledObject<T> p = allObjects.get(new IdentityWrapper<T>(obj));//获取对象缓存中的真实的对象

    if (p == null) {
        if (!isAbandonedConfig()) {
            throw new IllegalStateException(
                    "Returned object not currently part of this pool");
        } else {
            return; // Object was abandoned and removed
        }
    }

    synchronized(p) {
        final PooledObjectState state = p.getState();
        if (state != PooledObjectState.ALLOCATED) {//校验被归还的对象是否再次被归还(没有再次获取前)
            throw new IllegalStateException(
                    "Object has already been returned to this pool or is invalid");
        } else {
            p.markReturning(); // Keep from being marked abandoned
        }
    }

    long activeTime = p.getActiveTimeMillis();//获取该对象存活时间

    if (getTestOnReturn()) {//从配置中获取,由实现方传入,用于回归池校验
        if (!factory.validateObject(p)) {//校验失败,直接销毁,不用归还池中
            try {
                destroy(p);//里面代码很简单,就是从allObject和idle中删除,计数相应减一,交由facoty的实现方实现具体的销毁规则
            } catch (Exception e) {
                swallowException(e);
            }
            try {
                ensureIdle(1, false);
            } catch (Exception e) {
                swallowException(e);
            }
            updateStatsReturn(activeTime);
            return;
        }
    }

    try {
        factory.passivateObject(p);//对象 退化处理,就是放入池前,进行相应的处理,例如:释放资源等,交由实现方实现
    } catch (Exception e1) {
        swallowException(e1);
        try {
            destroy(p);
        } catch (Exception e) {
            swallowException(e);
        }
        try {
            ensureIdle(1, false);
        } catch (Exception e) {
            swallowException(e);
        }
        updateStatsReturn(activeTime);
        return;
    }

    if (!p.deallocate()) {
        throw new IllegalStateException(
                "Object has already been returned to this pool or is invalid");
    }

    int maxIdleSave = getMaxIdle();
    if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {//如果空闲对象已经大于配置的数量,直接销毁,不在放入池
        try {
            destroy(p);
        } catch (Exception e) {
            swallowException(e);
        }
    } else {//放入池中
        if (getLifo()) {//根据配置信息,采用FIFO(队列)
            idleObjects.addFirst(p);
        } else {//采用FILO(栈)
            idleObjects.addLast(p);
        }
        if (isClosed()) {
            // Pool closed while object was being added to idle objects.
            // Make sure the returned object is destroyed rather than left
            // in the idle object pool (which would effectively be a leak)
            clear();
        }
    }
    updateStatsReturn(activeTime);//更新活跃时长
}

2.3 空闲队列定期清理
在实例化该对象时,会调用startEvictor(getTimeBetweenEvictionRunsMillis()/*获取定期检测的时间,由配置传入/)

final void startEvictor(long delay) {
        synchronized (evictionLock) {
            if (null != evictor) {
                EvictionTimer.cancel(evictor);//取消之前的清理任务
                evictor = null;
                evictionIterator = null;
            }
            if (delay > 0) {//如果检测时间>0,执行该清理任务
                evictor = new Evictor();
                EvictionTimer.schedule(evictor, delay, delay);
            }
        }
    }


//真正的清理方法    
public void evict() throws Exception {
        assertOpen();

        if (idleObjects.size() > 0) {//空闲队列数量>0

            PooledObject<T> underTest = null;
            EvictionPolicy<T> evictionPolicy = getEvictionPolicy();//清理规则

            synchronized (evictionLock) {
                EvictionConfig evictionConfig = new EvictionConfig(
                        getMinEvictableIdleTimeMillis(),
                        getSoftMinEvictableIdleTimeMillis(),
                        getMinIdle());

                boolean testWhileIdle = getTestWhileIdle();

                for (int i = 0, m = getNumTests()/*每次清理的数量,由配置传入*/; i < m; i++) {
                    //下面就是真正的销毁方法,只是建单的规则校验,并交给factory的实现方真正的销毁的逻辑
                    if (evictionIterator == null || !evictionIterator.hasNext()) {
                        evictionIterator = new EvictionIterator(idleObjects);
                    }
                    if (!evictionIterator.hasNext()) {
                        // Pool exhausted, nothing to do here
                        return;
                    }

                    try {
                        underTest = evictionIterator.next();
                    } catch (NoSuchElementException nsee) {
                        // Object was borrowed in another thread
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        evictionIterator = null;
                        continue;
                    }

                    if (!underTest.startEvictionTest()) {
                        // Object was borrowed in another thread
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        continue;
                    }

                    // User provided eviction policy could throw all sorts of
                    // crazy exceptions. Protect against such an exception
                    // killing the eviction thread.
                    boolean evict;
                    try {
                        evict = evictionPolicy.evict(evictionConfig, underTest,
                                idleObjects.size());
                    } catch (Throwable t) {
                        // Slightly convoluted as SwallowedExceptionListener
                        // uses Exception rather than Throwable
                        PoolUtils.checkRethrow(t);
                        swallowException(new Exception(t));
                        // Don't evict on error conditions
                        evict = false;
                    }

                    if (evict) {
                        destroy(underTest);
                        destroyedByEvictorCount.incrementAndGet();
                    } else {
                        if (testWhileIdle) {
                            boolean active = false;
                            try {
                                factory.activateObject(underTest);
                                active = true;
                            } catch (Exception e) {
                                destroy(underTest);
                                destroyedByEvictorCount.incrementAndGet();
                            }
                            if (active) {
                                if (!factory.validateObject(underTest)) {
                                    destroy(underTest);
                                    destroyedByEvictorCount.incrementAndGet();
                                } else {
                                    try {
                                        factory.passivateObject(underTest);
                                    } catch (Exception e) {
                                        destroy(underTest);
                                        destroyedByEvictorCount.incrementAndGet();
                                    }
                                }
                            }
                        }
                        if (!underTest.endEvictionTest(idleObjects)) {
                            // TODO - May need to add code here once additional
                            // states are used
                        }
                    }
                }
            }
        }
        AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
            removeAbandoned(ac);
        }
    }    

通过上面源码一行行的解读,相信已经把对象池中管理的方式详细讲叙清楚。jedis客户端是基于pool2实现的,阅读jedis的源码 jedis源码分析,相信大家会对连接池具体的实现有很深入和具体的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值