apache commons pool2: 整体结构

2023-10-09 19:08

本文主要是介绍apache commons pool2: 整体结构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介

    在以往的一些工作中总接触到一个池的概念。这些池包括有线程池,对象池和连接池等。从池本身的概念来说,它是将一系列的资源事先准备好放在一个地方,等需要的时候直接拿过去用。而用完之后再放回来。和我们平常的需要使用资源再创建的方式相比,这种池的方式节省了创建和销毁资源的这么一个过程。所以说,对于一些比较比较稀缺的资源或者创建和销毁影响系统性能的资源,采用池的方式可以有效的提高整体性能。最近一段时间正好要用到一些数据库连接池等东西,趁这个时机把一些相关的部分好好的学习总结一下。如前面提到的,我们使用到的典型的线程池有jdk里的ExecutorService相关的一系列工具类(在这篇文章里有阐述),而一些典型的数据库连接池有cp03和dbcp。最近用到了dbcp,而它主要是基于commons-pool实现的,所以我们先从commons-pool2开始吧。

 

整体结构分析

    在正式分析commons-pool2的结构开始,我们设想一下,如果我们自己来设计一个object pool的话,我们该怎么来做呢?

    首先一个,我们从直接使用的角度来说,肯定需要一个ObjectPool对象,它负责保存我们需要访问的对象,我们把这个对象用完之后就返还给它。更细化一点的考虑的话,我们在使用前需要根据配置事先创建一些对象,后面需要使用的时候直接取就可以了。然后我们需要能够知道pool里面有多少可以用的对象。还有一个就是对象在被使用前是一个类似于初始化的状态,而使用完之后可能是另外的一个状态,既然我们希望对象能够被复用,在返回到pool里的时候可能还需要做一些重置的工作。

    除了这些以外,如果我们考虑对象的创建。我们可以将创建对象的职责给pool,这样pool同时既要管理对象的存取和回收又要管对象的创建和状态设置等。这有点像一个图书馆的管理员,他既要管借还书,还要管怎么造纸印书。这样想来,似乎管的职责有点多了。我们也可以将对象的创建单独分离处理作为一个factory来做。

    其实,通过前面的这些讨论,我们几乎也能创建一个像模像样的pool。如果结合commons-pool2的详细设计,我们会发现它的设计思路和我们也是基本上一致的。它主要由3个大的部分组成:

ObjectPool:专门实现对象存取和状态管理的池实现。我们直接操作的线程池就是定义在这里。值得注意的一点是这里定义的只是怎么来获取以及释放对象等操作,至于具体对象是怎么创建的,一般都通过独立的一个PooledObjectFactory来操心了。

 

PooledObject:这是commons-pools里比较有意思的一个类族。是对需要放到池里对象的一个包装类。添加了一些附加的信息,比如说状态信息,创建时间,激活时间,关闭时间等。这些添加的信息方便pool来管理和实现一些特定的操作。

 

PooledObjectFactory: 如我们前面所讨论的,管理具体对象的状态,比如创建,初始化,验证对象状态和销毁对象。

    通过我们的这些讨论,他们这三者就构成了一个object pool的基本框架。他们的关系可以用如下的一个图来描述:

    用一句话来概括他们整体的关系就是factory创建需要放入pool的对象,经过PooledObject包装一下就可以上架了。

    有一个地方需要注意一下,虽然我们这里将它划分成3个主要的部分,从更精确的细节来看,每一个类族里都有一些不同的实现,这里我们再针对每一类族做一个大体的介绍。

ObjectPool类族

    ObjectPool类族包含了以ObjectPool为代表的一系列pool,其中最主要的两类就是ObjectPool和KeyedObjectPool,他们分别针对普通的pool和以名值对映射的pool。和他们相关的整体几个类结构如下图:

    从前面的图里头我们可以看到,真正定义的接口就是ObjectPool和KeyedObjectPool,具体的实现里有GenericObjectPool, GenericKeyedObjectPool和SoftReferenceObjectPool。不管是哪一种他们都引用了PooledObject。 这里我们不详细分析具体实现的代码,我们先就前面的设想来验证一下他们的整体思路。既然是ObjectPool,那它就应该管borrowObject, returnObject之类的了。是不是呢?我们先看看ObjectPool这一块的代码:

Java代码   收藏代码
  1. public interface ObjectPool<T> {  
  2.     T borrowObject() throws Exception, NoSuchElementException,  
  3.             IllegalStateException;  
  4.   
  5.     void returnObject(T obj) throws Exception;  
  6.   
  7.     void invalidateObject(T obj) throws Exception;  
  8.   
  9.     void addObject() throws Exception, IllegalStateException,  
  10.             UnsupportedOperationException;  
  11.   
  12.     int getNumIdle();  
  13.   
  14.     int getNumActive();  
  15.   
  16.     void clear() throws Exception, UnsupportedOperationException;  
  17.   
  18.     void close();  
  19. }  

    这部分的代码很简单直接,主要就是包含了一个pool需要的基本操作功能,比如从pool里取对象的borrowObject,返回对象到pool里的returnObject,还有一些查找里面可用对象数量以及管理pool的方法。这里的clear方法是用来清空里面处于idle状态的对象,而close方法则用来关闭整个pool。他们两者的一个典型差别就是clear之后里面没有可以用的对象了,我们需要再创建一些对象放进去。而close之后则连pool都访问不了了。

    与ObjectPool对象的一个是KeyedObjectPool,它的操作方法基本上和ObjectPool一样,唯一的差别是它是基于key来操作的,所以所有相关的borrowObject, returnObject等操作都要提供key参数。

 

PooledObject类族

    如前所述,PooledObject主要是对需要被加入到pool里的对象提供一个包装,方便来查看或者统计一些对象信息,比如某个对象创建的时间,空闲时间以及活跃时间等。下面是PooledObject相关的类关系图:

 

    既然是一个简单的包装,我们就来看看具体需要访问的一些方法。如下是PooledObject里的基本方法定义:

Java代码   收藏代码
  1. public interface PooledObject<T> extends Comparable<PooledObject<T>> {  
  2.   
  3.     T getObject();  
  4.   
  5.     long getCreateTime();  
  6.   
  7.     long getActiveTimeMillis();  
  8.   
  9.     long getIdleTimeMillis();  
  10.   
  11.     long getLastBorrowTime();  
  12.   
  13.     long getLastReturnTime();  
  14.   
  15.     long getLastUsedTime();  
  16.   
  17.     @Override  
  18.     int compareTo(PooledObject<T> other);  
  19.   
  20.     @Override  
  21.     boolean equals(Object obj);  
  22.   
  23.     @Override  
  24.     int hashCode();  
  25.   
  26.     @Override  
  27.     String toString();  
  28.   
  29.     boolean startEvictionTest();  
  30.   
  31.     boolean endEvictionTest(Deque<PooledObject<T>> idleQueue);  
  32.   
  33.     boolean allocate();  
  34.   
  35.     boolean deallocate();  
  36.   
  37.     void invalidate();  
  38.   
  39.     void setLogAbandoned(boolean logAbandoned);  
  40.   
  41.     void use();  
  42.   
  43.     void printStackTrace(PrintWriter writer);  
  44.   
  45.     PooledObjectState getState();  
  46.   
  47.     void markAbandoned();  
  48.   
  49.     void markReturning();  
  50. }  

    这里列出的一大堆方法其实就是标注了各种操作,很多都是PooledObject本身实现加上去的。

    ok,有了前面这些管理对象和包装对象的东西,我们再来看看具体制造和销毁对象的部分。

PooledObjectFactory

    在commons-pool2里,我们专门抽象出来一个创建和销毁对象的接口,PooledObjectFactory。而具体对象的创建则由用户自定义实现。在本身的源代码里只有一个简单的抽象类BasePooledObjectFactory实现。我们来看看这个接口定义的方法:

Java代码   收藏代码
  1. public interface PooledObjectFactory<T> {  
  2.   
  3.   PooledObject<T> makeObject() throws Exception;  
  4.   
  5.   void destroyObject(PooledObject<T> p) throws Exception;  
  6.   
  7.   boolean validateObject(PooledObject<T> p);  
  8.   
  9.   void activateObject(PooledObject<T> p) throws Exception;  
  10.   
  11.   void passivateObject(PooledObject<T> p) throws Exception;  
  12. }  

    makeObject和destroyObject则分别用于创建销毁对象,很简单。而validateObject用于在每次创建对象放入到pool里或者从pool里取对象出来的时候验证是否对象合法。至于activeObject和passivateObject比较有意思。在这里给对象定义了一系列的状态。这里的设计假定所有在pool里可以被立马拿出去用的对象是一个idle状态,在拿到之后要用activateObject方法来激活一下。而对象要返回给pool的时候则要用passivateObject方法将它钝化。

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

其他

除了我们前面列举出来的这3个部分,还有org.apache.commons.pool2.impl和org.apache.commons.pool2.proxy这两个包。他们分别定义了前面定义的pool的默认实现和基于代理的实现。在后续的文章里会针对每个部分的细节实现做一个分析。

 

总结

    commons-pool2的整体结构并不复杂,可以将其划分为3个角色,一个管对象的进出口,一个管对象的包装,一个对象的创建。感觉好像一个产销结合的商业团体啊。有意思。

 

参考材料

http://commons.apache.org/proper/commons-pool/

转自 : http://shmilyaw-hotmail-com.iteye.com/blog/1983845

这篇关于apache commons pool2: 整体结构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/174941

相关文章

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Java集合中的链表与结构详解

《Java集合中的链表与结构详解》链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序的通过链表中的引用链接次序实现,文章对比ArrayList与LinkedList的结构差异,详细讲解了链表... 目录一、链表概念与结构二、当向单链表的实现2.1 准备工作2.2 初始化链表2.3 打印数据、链表长

创建springBoot模块没有目录结构的解决方案

《创建springBoot模块没有目录结构的解决方案》2023版IntelliJIDEA创建模块时可能出现目录结构识别错误,导致文件显示异常,解决方法为选择模块后点击确认,重新校准项目结构设置,确保源... 目录创建spChina编程ringBoot模块没有目录结构解决方案总结创建springBoot模块没有目录

SpringBoot利用树形结构优化查询速度

《SpringBoot利用树形结构优化查询速度》这篇文章主要为大家详细介绍了SpringBoot利用树形结构优化查询速度,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一个真实的性能灾难传统方案为什么这么慢N+1查询灾难性能测试数据对比核心解决方案:一次查询 + O(n)算法解决

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

Apache Ignite缓存基本操作实例详解

《ApacheIgnite缓存基本操作实例详解》文章介绍了ApacheIgnite中IgniteCache的基本操作,涵盖缓存获取、动态创建、销毁、原子及条件更新、异步执行,强调线程池注意事项,避免... 目录一、获取缓存实例(Getting an Instance of a Cache)示例代码:二、动态

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2

如何使用Maven创建web目录结构

《如何使用Maven创建web目录结构》:本文主要介绍如何使用Maven创建web目录结构的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录创建web工程第一步第二步第三步第四步第五步第六步第七步总结创建web工程第一步js通过Maven骨架创pytho