您的位置:首页 > 运维架构 > Apache

[置顶] apache-common-pool2源码分析

2017-10-31 10:03 435 查看

基础概念

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源码分析,相信大家会对连接池具体的实现有很深入和具体的理解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: