`
suhuanzheng7784877
  • 浏览: 704242 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Ff8d036b-05a9-33b5-828a-2633bb68b7e6
读金庸故事,品程序人生
浏览量:47745
社区版块
存档分类
最新评论

Apache的对象池化工具commons-pool

阅读更多

1.       前言

当我们的应用中创建一个十分最重量级的对象的时候,往往为了节省资源成本,使用单例模式,整个的应用中就只有一个对象供大家使用。这样是节省了不少资源,也是大多数应用的做法。不过如果遇到并发量十分大的情况下,并发访问的问题也就出现了。OK即使您不用加锁synchronized,利用ThreadLoacl进行安全变量的副本,但是维持变量副本的资源也是需要消耗资源的。而且对于一个重量级的对象的多个方法多个线程同时调用此对象的同一个局部变量,多个副本的维护实际上也是挺占用资源的。

2.       轻量级对象

当然不是说所有的对象都适合池化的。池化的对象是一个重量级对象,什么是重量级对象。回答这个问题先说说什么是轻量级对象。比如我们做Web系统的DAO(注意:这里绝对不包括EJBEAO),就是为了调用持久层框架完成增、删、改、查原子性操作。实际就算是轻量级的对象,DAO没必要含有太复杂的其他对象,如果需要其他辅助对象为其服务:比如事务插入、日志操作记录。使用AOP面向他的切面进行拦截即可。Spring有整套方案,不做扩展。创建这些对象,在启动Web应用的时候实例化放到容器中即可,想要,容器自动为您注入。容器保证了对象的线程安全,所以这些对象是轻量级对象。

3.       重量级对象

那什么又是重量级对象呢,咱们用一个谁都能想到的例子,数据库连接java.sql.Connection。为何说Connection是一个重量级对象呢?我们在JDBC编程的时候仅仅使用了很少量的代码即完成了数据库的连接操作。一个Connection对象为我们操作数据库做了什么?

1):通过JDBC的驱动Driver屏蔽底层数据库网络协议,让我们不必关心具体的数据库通讯协议(MysqlMysql的协议、OracleOracle的通讯协议)

2):通过数据库网络协议打开网络socket连接管道

3):根据建立的网络通道发送握手指令(所谓握手指令就是包含数据库用户名、数据库密码的二进制信息)

4):接收数据库端的握手结果信息再决定下面的通讯是否进行

关键是建立网络socket通道耗费资源着实不小。而且java.sql.Connection需要一直维持着这个网络通道。

相比于上面提到的DAO对象的创建,这个Connection对象创建的时候是不是确实显得历经沧桑。咱们举个例子,就像唐僧取经一样,李世民想要经书超度为他建功立业的亡魂,唐三藏就去了,历经千辛万苦取回来了,李世民让其诵念经文超度亡魂后发现这段时间那些死去的冤魂没再缠着他了,取回来的经文这个时候被李世民看经书占地方,下令烧掉了(垃圾回收器回收了)。过了一段时间又有亡魂开始缠着他了!怎么办?李世民说:“哦,御弟,麻烦你再去见佛祖一趟吧!”唐三藏之后又花了12年,再去西天见佛祖,取回了真经超度亡魂~~如果当时唐三藏说:“阿妹喂,陛下,当时您要是不下令烧掉,将经书交给我的大徒弟去管理,就不必这么麻烦~等我取回经书了,您也就快那什么啦”。

4.       对象池

对象池的概念和现实生活中的图书馆的管理极其相似。阅读这项看一本书,用读书卡去借一本书、看完了还回来,如果图书馆的书不够用了怎么办?那就麻烦图书采购小刘去市场买几本回来吧。这个本书太受欢迎了,原始的书的数量不够用啊。对象池就像是一个图书馆,图书管理员就像是对象调度器,借书人就像是调用对象的客户端。需要维护的就是图书馆和借书的记录凭证。这样看来资源需要维护图书馆和借书系统。但是这种维护在某种程度上来说是值得的。回到我们的编程世界中,Apachecommon-pool组件就是一个开源的对象池工具,我们可以借助它的接口,就可以将重量级的对象做池化。

5.       环境搭建

首先从apache站点下载commons-pool组件包。将lib下面的jar包拷贝到项目classpath中。因为此实话组件还依赖于其他的apachecommos组件——commons-collections。所以还需要将此jar包加入到classpath。笔者搭建好的环境如下

/ApacheCommonPool/lib/commons-collections-2.1.1.jar
/ApacheCommonPool/lib/commons-pool-1.5.6-javadoc.jar
/ApacheCommonPool/lib/commons-pool-1.5.6-sources.jar
/ApacheCommonPool/lib/commons-pool-1.5.6.jar
 简单的池化环境已经搭建完毕

6.       使用例程

在此历程中,我们测试一下Java常用对像,也是最通用的轻量级对象String的池化。再测试一下自定义的实体对象的池化。再次说明一点:String是绝对不适合做池化的,首先java.lang.String对象本身就不是什么重量级对象,初始化String对象也绝对不用经过什么西天取经的过程才能产生出来的,并且JVM已经对String做了池化处理。有一个String池维护已经创建好的字符串引用对象值。在此使用String仅仅是表示如何使用池化操作罢了。实际应用中,千万不要池化String对象。否则就有点得不偿失了。首先给出简单的POJO实体对象代码。

package key;

public class Person {

	String id;
	String name;

	public Person() {

	}

	public Person(String id, String name) {
		this.id = id;
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "id:" + id + "---name:" + name;
	}

}

 这个用户POJO类很简单,就只有idname属性。

下面是使用池工厂管理程序

 

/**
 * 池化工厂
 * @author liuyan
 */
class KeyedPoolableObjectFactorySample extends BaseKeyedPoolableObjectFactory {
	
	/**
	 * 创建对象方法
	 */
	@SuppressWarnings("unchecked")
	public Object makeObject(Object clsName) throws Exception {

		if (clsName == null || !(clsName instanceof String)
				|| "".equals(clsName)) {
			throw new RuntimeException("类名为空!");
		}

		System.out.println("创建一个新的对象:" + clsName);

		Class cls = Class.forName((String) clsName);
		Object obj = cls.newInstance();
		return obj;
	}

	@Override
	public void activateObject(Object key, Object obj) throws Exception {
		// TODO Auto-generated method stub
		super.activateObject(key, obj);
		System.out.println("激活对象");
	}

	@Override
	public void destroyObject(Object key, Object obj) throws Exception {
		// TODO Auto-generated method stub
		super.destroyObject(key, obj);
		System.out.println("销毁对象");
	}

	@Override
	public void passivateObject(Object key, Object obj) throws Exception {
		// TODO Auto-generated method stub
		super.passivateObject(key, obj);
		System.out.println("挂起对象");
	}

	@Override
	public boolean validateObject(Object key, Object obj) {
		// TODO Auto-generated method stub
		System.out.println("验证对象");
		return super.validateObject(key, obj);

	}

}

 池工厂对象就像是图书馆的调度管理员,需要创建新对象的时候就调用其makeObject()方法;其他的方法已经在程序中进行了说明。主要就是验证对象方法validateObject是验证是否已经存在了可复用的对象。在此历程中采用反射机制对目标对象进行实例化。

下面是使用程序

/**
 * 使用
 * @author liuyan
 *
 */
public class KeyedObjectPoolSample {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		Object obj = null;
		KeyedPoolableObjectFactory factory = new KeyedPoolableObjectFactorySample();

		KeyedObjectPoolFactory poolFactory = new StackKeyedObjectPoolFactory(
				factory);

		KeyedObjectPool pool = poolFactory.createPool();

		String key = null;

		try {

			key = "java.lang.String";

			obj = pool.borrowObject(key);
			obj = "obj1";
			// pool.returnObject(key, obj);
			obj = pool.borrowObject(key);
			pool.returnObject(key, obj);
			obj = pool.borrowObject(key);
			System.out.println(obj);

			System.out.println("============看另一个对象Person=============");

			key = "key.Person";

			Person person1 = (Person) pool.borrowObject(key);
			
			person1.setId("1");
			person1.setName("素还真");
			System.out.println(person1);
			pool.returnObject(key, person1);
			System.out.println(person1);

			Person person2 = (Person) pool.borrowObject(key);
			person2.setId("2");
			person2.setName("青阳子");

			Person person3 = (Person) pool.borrowObject(key);
			person3.setId("3");
			person3.setName("一页书");

			Person person4 = (Person) pool.borrowObject(key);
			person4.setId("4");
			person4.setName("业途灵");

			System.out.println(person1);
			System.out.println(person2);
			System.out.println(person3);
			System.out.println(person4);
			
			pool.returnObject(key, person3);
			Person person5 = (Person) pool.borrowObject(key);
			System.out.println(person5);
			

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				pool.close();
				System.out.println(pool);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

}

 首先先建立一个字符串对象,引用值为 “obj1”。接着从对象池中借一个字符串对象出来obj指向这个借出来的对象,若池中有可复用的对象,直接给之,如果没有,调用makeObject()造一个新的对象出来给obj引用。用完后调用returnObject方法将对象还给池子。咱们再看下面使用Person对象,先从池中借一个Person对象person1。当然池子里面现在还没有任何Person对象。对池中对象赋值后,还给了池子。这个时候池子中就有一个被使用过的,并且属性已经发生改变的对象。下面person2变量向池子借了一个Person对象,此时池子里已经有了一个可复用的对象。那么不必调用makeObject方法,直接将已有的对象返回给客户端即可。然后对其赋值。把刚刚的1素还真改成了2青阳子,那么这个时候刚才的person1也是2青阳子,person1的引用指针没变,仅仅是引用的那块区域的字符串值发生了变化。之后还没等这个对象返还给池子呢,person3变量就向池子要对象,池子说:“等等,我给你make一个啊”,之后又调用了markObject方法创建了一个新的对象。这个新的对象就是3一页书。往下的4业途灵也是新的。当执行到

	pool.returnObject(key, person3);
	Person person5 = (Person) pool.borrowObject(key);
	System.out.println(person5);

 发现person5是刚刚归还的复用对象——3一页书。执行后控制台如下

创建一个新的对象:java.lang.String
激活对象
验证对象
创建一个新的对象:java.lang.String
激活对象
验证对象
验证对象
挂起对象
激活对象
验证对象
~~~
============看另一个对象Person=============
创建一个新的对象:key.Person
激活对象
验证对象
id:1---name:素还真
验证对象
挂起对象
id:1---name:素还真
激活对象
验证对象
创建一个新的对象:key.Person
激活对象
验证对象
创建一个新的对象:key.Person
激活对象
验证对象
id:2---name:青阳子
id:2---name:青阳子
id:3---name:一页书
id:4---name:业途灵
验证对象
挂起对象
激活对象
验证对象
id:3---name:一页书
org.apache.commons.pool.impl.StackKeyedObjectPool contains 0 distinct pools:

 经过这个例子我们还应该清楚一个事实就是像这个可对局部变量访问(get)、赋值(set)的对象也不适合池化。因为别人用过了这样的对象,实际上留下了别人用过的痕迹。这样确实会造成局部变量用起来会不一致的线程安全问题。应该是对外仅仅提供服务的方法,并且不具备访问局部变量的对象,并且创建时十分消耗资源的对象才适合池化。到底是池化还是单例,这个当然没有绝对的答案,一切得看您的实际系统需要怎样做更合理。

4
3
分享到:
评论
1 楼 jxFY 2018-04-08  
   

相关推荐

    commons-pool 等jar包

    Apache Commons Pool库正是提供了这种对象池服务,它为各种可池化对象提供了一种通用的框架。 DBCP则是基于commons-pool的数据库连接池实现。它提供了数据库连接的创建、管理和分配服务。在DBCP中,数据库连接被视...

    commons-pool-1.3.jar 和commons-dbcp-1.2.2.jar

    在"commons-pool-1.3.jar"中,它实现了基本的Pool接口,提供了对象池的创建、管理和维护功能。 Apache Commons DBCP(Database Connection Pool)是基于Apache Commons Pool的数据库连接池组件。它提供了一个数据库...

    commons-pool资源下载

    commons-pool资源下载,东西齐全,包括api文档开发,Apache的对象池化工具commons-pool 当我们的应用中创建一个十分最重量级的对象的时候,往往为了节省资源成本,使用单例模式,整个的应用中就只有一个对象供大家...

    commo-pool, commons-pool commons-pool commons-pool

    Apache Commons Pool 是一个Java对象池库,主要用于提供各种对象池化的实现,以便高效地管理和复用有限的资源。标题中的"commo-pool, commons-pool commons-pool commons-pool"可能是由于输入错误,正确的应该是...

    commons-dbcp-1.4.jar和commons-pool-1.5.6.jar

    `commons-pool-1.5.6.jar` 提供了一套通用的对象池服务,DBCP利用它来管理数据库连接对象。对象池技术可以有效地复用对象,减少创建和销毁对象的开销。在DBCP中,Commons Pool主要负责以下任务: 1. **...

    commons-pool2-2.6.2.jar

    Redis 的Cluster集群搭建依赖的jar,优秀的开源对象池化组件apache-commons-pool2,它对对象池化操作进行了很好的封装,我们只需要根据自己的业务需求重写或实现部分接口即可,使用它可以快速的创建一个方便,简单,...

    commons-pool2-2.4.2.jar

    Apache Commons Pool2是一个Java对象池库,用于管理资源对象,如数据库连接或网络套接字。这个库的主要目的是提高性能和资源效率,通过重用已创建的对象而不是每次需要时都创建新的。在给定的场景中,`commons-pool2...

    commons-pool2-2.8.1.jar

    Apache Commons Pool 是一个广泛使用的开源组件,主要用于提供对象池化的实现。在Java世界里,对象池化是一种优化资源管理的重要技术,通过复用已创建的对象,避免频繁的创建和销毁过程,从而提升系统性能。最新版本...

    commons-pool-1.3.jar+commons-collections-3.2.1.jar

    标题中的"commons-pool-1.3.jar"和"commons-collections-3.2.1.jar"是两个Java库,它们在开发基于SSH(Struts、Spring、Hibernate)架构的应用时常常被用到。SSH是一种流行的企业级Java应用框架,用于构建高性能、可...

    commons-pool-1.6.jar.zip

    标题中的"commons-pool-1.6.jar.zip"表明这是一个包含Apache Commons Pool 1.6版本的压缩文件,其中的核心组件是`commons-pool-1.6.jar`。 **Apache Commons Pool 概述** Apache Commons Pool 是Apache软件基金会的...

    commons-collections-3.1.jar;commons-dbcp-1.2.1.jar;commons-pool-1.2.jar

    3. **Apache Commons Pool** (commons-pool-1.2.jar):这是Apache Commons的一个子项目,提供了通用的对象池服务。对象池化是一种设计模式,用于减少创建和销毁对象的开销,通过重用已创建的对象来提高性能。DBCP...

    commons-pool2-2.6.0-bin.zip

    1. **通用对象池接口**:`org.apache.commons.pool2.PooledObjectFactory` 和 `org.apache.commons.pool2.Poolable` 接口,定义了对象池的基本操作和对象的池化行为。 2. **对象池实现**:`org.apache.commons.pool2...

    jdbc用到的jar包(commons-collections-3.1.jar、commons-dbcp-1.2.2.jar、commons-pool.jar)

    这是Apache Commons项目的一个子项目,它提供了一个基于池化的数据库连接管理库。在使用JDBC时,数据库连接的创建和关闭是非常耗时的,DBCP通过维护一个连接池,可以复用已存在的数据库连接,从而提高应用程序的...

    commons-dbcp-1.4和commons-pool-1.6驱动包下载(亲测可用)

    总的来说,Apache Commons DBCP 1.4 和 Commons Pool 1.6 是Java开发中不可或缺的工具,它们为高效、可靠的数据库连接管理提供了强大支持。这两个库的配合使用,能够帮助开发者构建出更加健壮、高性能的应用系统。...

    commons-dbcp-1.2.2.jar &commons-pool-1.3.jar

    `commons-pool-1.3.jar`包含PoolableObjectFactory、GenericObjectPool和PooledObject等关键类,它们负责对象的创建、维护和回收,确保池中对象的有效性和可用性。 在Tomcat服务器中,DataSource通常通过`server....

    commons-dbcp-1.2.1.jar commons-pool-1.3.jar struts-legacy.jar

    - `commons-pool-1.3.jar` 是这个对象池库的1.3版本。在DBCP中,它被用来管理数据库连接,确保连接的高效利用和管理。 - 这个库提供了可扩展的对象池接口和实现,可以用于各种类型的对象,不仅仅局限于数据库连接...

    commons-beanutils.jar commons-collections-3.1.jar commons-pool-1.2.jar

    这里提到的三个JAR文件——`commons-beanutils.jar`、`commons-collections-3.1.jar`和`commons-pool-1.2.jar`,都是Apache Commons项目的一部分,分别涉及Bean操作、集合操作和对象池化。 **1. `commons-beanutils...

    commons-pool2-2.4.2.zip

    为了避免重新造轮子,我们可以使用优秀的开源对象池化组件apache-commons-pool2,它对对象池化操作进行了很好的封装,我们只需要根据自己的业务需求重写或实现部分接口即可,使用它可以快速的创建一个方便,简单,...

    jedis-2.9.0+commons-pool2-2.4.2redis依赖包

    Apache Commons Pool 2是一个通用的对象池服务,它是Apache Commons组件的一部分。在Jedis中,它被用来实现对象池化,特别是Redis连接的池化。连接池允许应用程序重复使用已经创建的Redis连接,而不是每次需要时都...

Global site tag (gtag.js) - Google Analytics