common-pool2 学习:thrift连接池的另一种实现
对象池是一种很实用的技术,经典的例子就是数据库连接池。去年曾经从零开始写过一个thrift客户端连接池。如果不想重造轮子,可以直接在apache开源项目commons-pool的基础上开发。
步骤:
一、定义对象工厂
package test.cn.mwee.service.paidui.pool; import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException; public class TProtocolFactory
extends BasePooledObjectFactory<TProtocol> { private String host;
private int port;
private boolean keepAlive = true; public TProtocolFactory(String host, int port, boolean keepAlive) {
this.host = host;
this.port = port;
this.keepAlive = keepAlive;
} @Override
public TProtocol create() throws TTransportException {
TSocket tSocket = new TSocket(host, port);
TTransport tTransport = new TFramedTransport(tSocket);
tTransport.open();
return new TCompactProtocol(tTransport);
} @Override
public PooledObject<TProtocol> wrap(TProtocol protocol) {
return new DefaultPooledObject<>(protocol);
} /**
* 对象钝化(即:从激活状态转入非激活状态,returnObject时触发)
*
* @param pooledObject
* @throws TTransportException
*/
@Override
public void passivateObject(PooledObject<TProtocol> pooledObject) throws TTransportException {
if (!keepAlive) {
pooledObject.getObject().getTransport().flush();
pooledObject.getObject().getTransport().close();
}
} /**
* 对象激活(borrowObject时触发)
*
* @param pooledObject
* @throws TTransportException
*/
@Override
public void activateObject(PooledObject<TProtocol> pooledObject) throws TTransportException {
if (!pooledObject.getObject().getTransport().isOpen()) {
pooledObject.getObject().getTransport().open();
}
} /**
* 对象销毁(clear时会触发)
* @param pooledObject
* @throws TTransportException
*/
@Override
public void destroyObject(PooledObject<TProtocol> pooledObject) throws TTransportException {
passivateObject(pooledObject);
pooledObject.markAbandoned();
} /**
* 验证对象有效性
*
* @param p
* @return
*/
@Override
public boolean validateObject(PooledObject<TProtocol> p) {
if (p.getObject() != null) {
if (p.getObject().getTransport().isOpen()) {
return true;
}
try {
p.getObject().getTransport().open();
return true;
} catch (TTransportException e) {
e.printStackTrace();
}
}
return false;
}
}
有二个关键的方法,需要重写:activateObject(对象激活) 及 passivateObject(对象钝化)
二、定义对象池
package test.cn.mwee.service.paidui.pool; import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; /**
* Created by yangjunming on 6/7/16.
*/
public class AutoClearGenericObjectPool<T> extends GenericObjectPool<T> { public AutoClearGenericObjectPool(PooledObjectFactory<T> factory) {
super(factory);
} public AutoClearGenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config) {
super(factory, config);
} @Override
public void returnObject(T obj) {
super.returnObject(obj);
//空闲数>=激活数时,清理掉空闲连接
if (getNumIdle() >= getNumActive()) {
clear();
}
} }
common-pools提供了对象池的默认实现:GenericObjectPool 但是该对象池中,对于处于空闲的对象,需要手动调用clear来释放空闲对象,如果希望改变这一行为,可以自己派生自己的子类,重写returnObject方法,上面的代码中,每次归还对象时,如果空闲的对象比激活的对象还要多(即:一半以上的对象都在打酱油),则调用clear方法。
三、使用示例:
package test.cn.mwee.service.paidui.pool; import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.thrift.protocol.TProtocol; import java.util.ArrayList;
import java.util.List;
import java.util.Random; /**
* thrift 连接池测试
*/
public class ProtocolPoolTest { public static void main(String[] args) throws Exception { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxTotal(10);
poolConfig.setMinIdle(1);
poolConfig.setTestOnBorrow(true); ObjectPool<TProtocol> pool = new AutoClearGenericObjectPool<>(
new TProtocolFactory("127.0.0.1", 13041, true), poolConfig); List<TProtocol> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
TProtocol protocol = pool.borrowObject();
System.out.println(protocol.toString());
if (i % 2 == 0) {
//10个连接中,将偶数归还
pool.returnObject(protocol);
} else {
list.add(protocol);
}
} Random rnd = new Random();
while (true) {
System.out.println(String.format("active:%d,idea:%d", pool.getNumActive(), pool.getNumIdle()));
Thread.sleep(5000);
//每次还一个
if (list.size() > 0) {
int i = rnd.nextInt(list.size());
pool.returnObject(list.get(i));
list.remove(i);
} //直到全部还完
if (pool.getNumActive() <= 0) {
break;
}
} System.out.println("------------------------"); list.clear();
//连接池为空,测试是否能重新创建新连接
for (int i = 1; i <= 10; i++) {
TProtocol protocol = pool.borrowObject();
System.out.println(protocol.toString());
if (i % 2 == 0) {
pool.returnObject(protocol);
} else {
list.add(protocol);
}
} while (true) {
System.out.println(String.format("active:%d,idea:%d", pool.getNumActive(), pool.getNumIdle()));
Thread.sleep(5000);
if (list.size() > 0) {
int i = rnd.nextInt(list.size());
pool.returnObject(list.get(i));
list.remove(i);
} if (pool.getNumActive() <= 0) {
pool.close();
break;
}
} }
}
注:需要从对象池取一个对象时,调用borrowObject(背后会调用activeObject激活对象),类似的,对象使用完之后,需要调用returnObject将对象放回对象池(背后会调用passivateObject使对象钝化)
输出:
org.apache.thrift.protocol.TCompactProtocol@146044d7
org.apache.thrift.protocol.TCompactProtocol@1e9e725a
org.apache.thrift.protocol.TCompactProtocol@516be40f
org.apache.thrift.protocol.TCompactProtocol@3c0a50da
org.apache.thrift.protocol.TCompactProtocol@3c0a50da
org.apache.thrift.protocol.TCompactProtocol@646be2c3
org.apache.thrift.protocol.TCompactProtocol@646be2c3
org.apache.thrift.protocol.TCompactProtocol@797badd3
org.apache.thrift.protocol.TCompactProtocol@797badd3
org.apache.thrift.protocol.TCompactProtocol@77be656f
active:5,idea:1
active:4,idea:2
active:3,idea:0
active:2,idea:1
active:1,idea:0
------------------------
org.apache.thrift.protocol.TCompactProtocol@221af3c0
org.apache.thrift.protocol.TCompactProtocol@62bd765
org.apache.thrift.protocol.TCompactProtocol@23a5fd2
org.apache.thrift.protocol.TCompactProtocol@78a2da20
org.apache.thrift.protocol.TCompactProtocol@78a2da20
org.apache.thrift.protocol.TCompactProtocol@dd3b207
org.apache.thrift.protocol.TCompactProtocol@dd3b207
org.apache.thrift.protocol.TCompactProtocol@551bdc27
org.apache.thrift.protocol.TCompactProtocol@551bdc27
org.apache.thrift.protocol.TCompactProtocol@58fdd99
active:5,idea:1
active:4,idea:2
active:3,idea:0
active:2,idea:1
active:1,idea:0
Process finished with exit code 0
从输出上看,归还对象后,再次取出时,并没有创建新对象,而是直接使用了对象池中已经空闲的对象。当对象池中的所有对象都归还变成空闲并被clear后,再次从对象池中借对象时,会重新创建对象。
common-pool2 学习:thrift连接池的另一种实现的更多相关文章
- 用apache commons-pool2建立thrift连接池
Apache Thrift 是 Facebook 实现的一种高效的.支持多种编程语言的远程服务调用的框架.具体的介绍可以看Apache的官方网站:http://thrift.apache.org/ . ...
- rpc框架之 thrift连接池实现
接前一篇rpc框架之HA/负载均衡构架设计 继续,写了一个简单的thrift 连接池: 先做点准备工作: package yjmyzz; public class ServerInfo { publi ...
- Java的JDBC原生态学习以及连接池的用法
JDBC是什么 JDBC(Java Data Base Connectivity)是Java访问数据库的桥梁,但它只是接口规范,具体实现是各数据库厂商提供的驱动程序(Driver). 应用程序.JDB ...
- nodejs的mysql模块学习(十)连接池集群配置选项
连接池集群选项 canRetry : 如果true ,连接池集群会在连接失败时尝试连接 默认true removeNodeErrorCount : 如果连接失败,节点的errCount增加.当erro ...
- nodejs的mysql模块学习(九)连接池集群
连接池集群 连接池集群可以提供多个主机连接 创建连接池集群 //创建连接池集群 var poolCluster = mysql.createPoolCluster(); //添加配置 config是一 ...
- nodejs的mysql模块学习(七)连接池事件
连接池事件 connection 当建立连接的时候就会触发 pool.on('connection' function(connection){ connection.query('SET SESSI ...
- nodejs的mysql模块学习(六)连接池的创建和使用
介绍 在 软件工程 , 连接池 是一个 高速缓存 的 数据库连接 维持,使得连接可以当需要将来向数据库请求重复使用. [ 来源请求 ] 连接池用于提高数据库上执行命令的性能. 打开并保持每个用户的数据 ...
- 三、redis学习(jedis连接池)
一.jedis连接池 二.jedis连接池+config配置文件 三.jedis连接池+config配置文件+util工具类 util类 public class JedisPoolUtils { / ...
- python学习--python 连接SQLServer数据库(两种方法)
1. python 学习.安装教程参照: http://www.runoob.com/python/python-tutorial.html 2. 集成开发环境 JetBrains PyCharm C ...
随机推荐
- PHP实现全排列(递归算法)
算法描述:如果用P表示n个元素的全排列,而Pi表示n个元素中不包含元素i的全排列,(i)Pi表示在排列Pi前面加上前缀i的排列,那么n个元素的全排列可递归定义为: ① 如果n=1,则排列P只有一 ...
- TeamCity : Build 基本配置
前文中我们在 TeamCity 中创建了一个项目 HelloApp,并在这个项目中创建了一个名为 HelloAppDailyBuild 的Build 用来编译 demo 程序.本文我们将详细介绍 Bu ...
- 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 6 - 业务逻辑
Part 3: 设计逻辑层:核心开发 如前所述,我们的解决方案如下所示: 下面我们讨论整个应用的结构,根据应用中不同组件的逻辑相关性,分离到不同的层中,层与层之间的通讯通过或者不通过限制.分层属于架构 ...
- h1、h2、h3标签及strong标签对页面seo的影响
今天和大家来聊下h1,h2,h3,strong几个标签,在网页中的使用对页面seo的影响,也阐述了个人的一些想法. 首先简要讲下H标签及strong标签的含义:<h1>.<h2> ...
- MySql 修改列的注释信息的方法
1. 问题 已经有很多数据的按照业务逻辑分表的一系列表修改一个字段(类型,如-1:默认值,1:表示'人员id',2:表示'公司id')的注释2. 解决方法 1> 使用alter ...
- HTTPS和HTTP的概念和区别
HTPPS和HTTP的概念 HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP ...
- mysql 插入数据失败防止自增长主键增长的方法
mysql设置了自增长主键ID,插入失败的那个自增长ID也加一的,比如失败5个,下一个成功的不是在原来最后成功数据加1,而是直接变成加6了,失败次数一次就自动增长1了,能不能让失败的不增长的? 或者说 ...
- 在SharePoint 2013 之中使用JS从Add-in程序中读取用户配置文件的属性
经过无数次的实验,只有这个程序可以运行正常 ,代码贴出来纯的JSOM,在我的实验环境老是返回未知错误,为了这一个简单的任务,我已经搞了2天了,不过终于搞出来了,使用各种方法后,还有使用代码. func ...
- low security dvwa--SQL Injection
登录dvwa后,点击左边的"SQL Injection",出现以下界面: 下面做一些学习总结. 第一步:用 "order by n" 获得表中的属性列数,它的意 ...
- ListView和Adapter数据适配器的简单介绍
ListView 显示大量相同格式数据 常用属性: listSelector listView每项在选中.按下等不同状态时的Drawable divider ...