我们在服务器开发的过程中,往往会有一些对象,它的创建和初始化需要的时间比较长,比如数据库连接,网络IO,大数据对象等。在大量使用这些对象时,如果不采用一些技术优化,就会造成一些不可忽略的性能影响。一种办法就是使用对象池,每次创建的对象并不实际销毁,而是缓存在对象池中,下次使用的时候,不用再重新创建,直接从对象池的缓存中取即可。为了避免重新造轮子,我们可以使用优秀的开源对象池化组件apache-common-pool2,它对对象池化操作进行了很好的封装,我们只需要根据自己的业务需求重写或实现部分接口即可,使用它可以快速的创建一个方便,简单,强大对象连接池管理类。
下面先看看主要的几个种要的接口和实现类:
- PooledObjectFactory<T>: 对象工厂,在需要的时候生成新的对象实例,并放入池中,一般使用抽象类BasePooledObjectFactory<T>,在GenericObjectPool中,有两个我们会用到的方法:public Jedis create() throws Exception 创建对象,public PooledObject<T> wrap(T t) 封装为池化对象。其它还有一些方法,可以查看下面的MyJedisFactory代码。
- ObjectPool: 对象池,用于存储对象,并管理对象的入池和出池。对象池的实现类是 GenericObjectPool<T>;在GenericObjectPool中,有两个我们会用到的方法:public T borrowObject() throws Exception 从对象池中获取一个对象,public void returnObject(T obj) 对象使用完之后,归还到对象池,其它还有一些方法,比如关闭对象池,销毁对象池等。
- BaseObjectPoolConfig: 池属性,用于设置连接池的一些配置信息,比如最大池容量、超过池容量后的处理逻辑等。池属性的实现类是:GenericObjectPoolConfig;
- Object: 池对象,由对象工厂负责创建,并放入到对象池中;需要使用时从对象池中取出,执行对象的业务逻辑,使用完后再放回对象池。
下面我们来用代码实现jedis的连接池,类关系图如下:
1,引入依赖
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.10.0</version> </dependency> <!-- 下面这个是为了使用jedis,但是我们不用它自带的redisPool --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.1</version> </dependency>
2,创建MyJedisFactory类,继承BasePooledObjectFactory<Jedis>
public class MyJedisFactory extends BasePooledObjectFactory<Jedis> { //计数,连接池内的对象个数 private AtomicInteger sum = new AtomicInteger(0); private static String HOST = "******"; private static int PORT = 6379; private static String PASSWORD = "****"; /** * 创造对象 * @return * @throws Exception */ @Override public Jedis create() throws Exception { System.out.println("创造了 " + sum.incrementAndGet() + "个对象"); Jedis jedis = new Jedis(HOST, PORT); jedis.auth(PASSWORD); return jedis; } /** * 破坏对象 * @param p * @throws Exception */ @Override public void destroyObject(PooledObject<Jedis> p) throws Exception { System.out.println("破坏" ); super.destroyObject(p); } /** * 封装为池化对象 * @param jedis * @return */ @Override public PooledObject<Jedis> wrap(Jedis jedis) { return new DefaultPooledObject<Jedis>(jedis); } /** * 拿取时调用 * @param p * @throws Exception */ @Override public void activateObject(PooledObject<Jedis> p) throws Exception { super.activateObject(p); System.out.println("拿取" + sum.get()); } /** * 返还池子里时调用 * @param pooledObject * @throws Exception */ @Override public void passivateObject(PooledObject<Jedis> pooledObject) throws Exception{ super.passivateObject(pooledObject); System.out.println("返还" + sum.get()); } /** * * @param p * @return */ @Override public boolean validateObject(PooledObject<Jedis> p){ System.out.println("校验" ); return super.validateObject(p); } }
3,创建MyJedisPool类,继承GenericObjectPool<Jedis>
public class MyJedisPool extends GenericObjectPool<Jedis> { public MyJedisPool(PooledObjectFactory<Jedis> factory) { super(factory); } public MyJedisPool(PooledObjectFactory<Jedis> factory, GenericObjectPoolConfig config) { super(factory, config); } public MyJedisPool(PooledObjectFactory<Jedis> factory, GenericObjectPoolConfig config, AbandonedConfig abandonedConfig) { super(factory, config, abandonedConfig); } }
4,测试testPool类
public class testPool { public static void main(String[] args) { PooledObjectFactory<Jedis> fac = new MyJedisFactory(); GenericObjectPool<Jedis> pool = new MyJedisPool(fac,new GenericObjectPoolConfig()); int testCount = 20; CountDownLatch c = new CountDownLatch(testCount); for (int i = 0; i < testCount; i++) { new Thread(() -> { testPool(pool); c.countDown(); }).start(); } try { c.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("活跃数: " + pool.getNumActive()); System.out.println("空闲数: " + pool.getNumIdle()); } static void testPool(GenericObjectPool<Jedis> pool) { Jedis myJedis = null; try { // 从池中获取对象 myJedis = pool.borrowObject(); // 使用对象 System.out.println(myJedis.get("*********")); } catch (Exception e) { try { // 出现错误将对象置为失效 pool.invalidateObject(myJedis); myJedis = null; } catch (Exception ex) { } } finally { try { if (null != myJedis) { // 使用完后必须 returnObject pool.returnObject(myJedis); } } catch (Exception e) { } } } }
下面我们看看运行结果: