您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
基于Commons-Pool2实现自己的redis连接池
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
基于Commons-Pool2实现自己的redis连接池
自猿其说Tech
2021-06-16
IP归属:未知
111560浏览
计算机编程
在服务器开发的过程中,往往会有一些对象,它们的创建和初始化所花费时间比较长,例如数据库连接,网络IO,大数据对象等等。在频繁使用这些对象时,如果不采用一些技术优化,就会造成很大的性能影响。其中的一种解决方案就是使用对象池,每次创建的对象使用完毕后并不实际销毁,而是缓存在对象池中,下次使用的时候,不用再重新创建,直接从对象池的缓存中取即可。为了避免重新造轮子,我们可以使用优秀的开源对象池化组件apache-common-pool2,它针对对象池化操作进行了很好的封装,我们只需要根据自己的业务需求重写或实现部分接口即可,使用它可以快速的创建一个简单、强大的对象连接池。 下面先看看主要的几个主要的接口和实现类: - PooledObjectFactory<T>: 对象工厂,在需要的时候生成新的对象实例,并放入池中,一般使用抽象类BasePooledObjectFactory<T>,在BasePooledObjectFactory中,有两个我们会用到的方法:public Jedis create() throws Exception 创建对象,public PooledObject<T> wrap(T t) 封装为池化对象,当然还有其它还有一些方法,可以查看下面的MyJedisFactory代码。 - ObjectPool<T>: 对象池,用于存储对象,并管理对象的入池和出池。对象池的实现类是 GenericObjectPool<T>,当我们使用时如果需要修改,就可以继承GenericObjectPool<T>类重写对应的方法即可,否则就直觉使用。在GenericObjectPool<T>中,有两个我们会用到的方法:public T borrowObject() throws Exception 从对象池中获取一个对象,public void returnObject(T obj) 对象使用完之后,归还到对象池,当然还有一些方法,比如关闭对象池,销毁对象池等。 - BaseObjectPoolConfig: 池属性,用于设置连接池的一些配置信息,比如最大池容量、超过池容量后的处理逻辑等。池属性的实现类是:GenericObjectPoolConfig。 T: 池对象,由对象工厂负责创建,并放入到对象池中;需要使用时从对象池中取出,执行对象的业务逻辑,使用完后再放回对象池。 它们的类关系图如下: ![](//img1.jcloudcs.com/developer.jdcloud.com/cde2709f-46fd-4112-a3fb-49a0fbd7b5de20210616143528.png) 下面我们用代码来简单地实现redis的连接池: 1,引入依赖 ```java <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> ```java 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> ```java 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类 ```java 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) { } } } } ``` 我们的PoolConfig用的是GenericObjectPoolConfig,它容纳的对象的最大数量为8,因此我们可以看到如下的运行结果: ![](//img1.jcloudcs.com/developer.jdcloud.com/b2cc818c-3c80-4490-8a71-df1cf06c8ddc20210616144356.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/88b45394-ccfa-4159-bdaf-67ac59c6f06920210616144417.png) 大名鼎鼎的redis的java客户端jedis的连接池就是利用Commons-Pool2实现的,大家有时间可以去看看源码。 ------------ ###### 自猿其说Tech-JDL京东物流技术发展部 ###### 作者:冷链技术部-平台研发组 曹志星 ------------
原创文章,需联系作者,授权转载
上一篇:当我们谈论前端组件化的时候,我们在谈论什么
下一篇:DBCP数据库连接打满原因分析
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
自猿其说Tech
文章数
426
阅读量
2149963
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149963
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号