Apache Thrift 是 Facebook 实现的一种高效的、支持多种编程语言的远程服务调用的框架。具体的介绍可以看Apache的官方网站:http://thrift.apache.org/ 。今天并不介绍thrift如何使用,只是演示一下如何使用commons-pool2建立thrift连接池,这样可以快速访问服务端。
我演示的thrift接口如下所示:
public interface Iface { public String genNewKTVOrder(com.ethank.thrift.iface.service.TOrder torder) throws org.apache.thrift.TException; public String genWeiXinPreOrder(String orderId, String body) throws org.apache.thrift.TException; public String genPreKTVGoodsOrder(String reserveGoodsId, String reserveBoxId, String goodsList, String sumPrice, int userId, String ktvId) throws org.apache.thrift.TException; public String genWeiXinQRCode(String orderId, String body) throws org.apache.thrift.TException; }
这些代码都是通过thrift自动生成的,具体如何操作可以看网上搜索一些thrift教程。
thrift客户端是这样一个内部类:
public static class Client extends org.apache.thrift.TServiceClient implements Iface
我的思路实在pool中放入org.apache.thrift.transport.TSocket对象,其工厂方法如下:
import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.thrift.transport.TSocket; public class ConnectionFactory extends BasePooledObjectFactory<TSocket>{ @Override public TSocket create() throws Exception { TSocket transport = new TSocket("192.168.1.222", 34568, 2000); //建立TSocket,根据具体情况可以修改 transport.open(); return transport; } @Override public boolean validateObject(org.apache.commons.pool2.PooledObject<TSocket> p){ //校验对象有效性 TSocket transport = p.getObject();return transport.isOpen(); } @Override public PooledObject<TSocket> wrap(TSocket obj) { //创建包装对象,包装对象是真正放在pool中的对象 return new DefaultPooledObject<TSocket>(obj); } @Override public void destroyObject(PooledObject<TSocket> p) throws Exception { //销毁对象,关闭链接 if (p.getObject().isOpen()) { p.getObject().close(); } } }
实际调用中并不是用的TSocket,而是Client对象,为此建立ConnectionManager利用TSocket建立Client对象:
import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TSocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ethank.thrift.iface.service.EthankOrderService; public class ConnectionManager { private static final Logger LGR = LoggerFactory.getLogger(ConnectionManager.class); private static GenericObjectPool<TSocket> pool; static { ConnectionFactory connectionFactory = new ConnectionFactory(); GenericObjectPoolConfig config = new GenericObjectPoolConfig(); config.setMaxIdle(10); //最大空闲数量 config.setMaxTotal(20); //连接池最大数量 config.setMinIdle(3); //最小空闲数量 config.setTestOnBorrow(true); //在从pool中去对象时进行有效性检查,会调用工厂中的validateObject config.setMaxWaitMillis(1000); //提取对象时最大等待时间,超时会抛出异常 config.setMinEvictableIdleTimeMillis(60000); // 最小的空闲对象驱除时间间隔,空闲超过指定的时间的对象,会被清除掉 config.setTimeBetweenEvictionRunsMillis(30000);//后台驱逐线程休眠时间 config.setNumTestsPerEvictionRun(3); //设置驱逐线程每次检测对象的数量 config.setTestWhileIdle(true); //是否对空闲对象使用PoolableObjectFactory的validateObject校验, pool = new GenericObjectPool<TSocket>(connectionFactory, config); } public static EthankOrderService.Client getThriftConnetion(){ TSocket socket; try { socket = pool.borrowObject(); TProtocol protocol = new TCompactProtocol(socket); EthankOrderService.Client client= new EthankOrderService.Client(protocol); client.socket = socket; return client; } catch (Exception e) { e.printStackTrace(); } return null; } public static void returnThriftConnetion(EthankOrderService.Client client){ pool.returnObject(client.socket); } public static int getPoolObjectNum() { return pool.getNumIdle(); } }
测试类做测试:
public static void main(String[] args) { for (int i = 0; i < 20; i++) { try { new Thread(new Runnable() { public void run() { EthankOrderService.Client client = null; try { client = ConnectionManager.getThriftConnetion(); String re = client.genWeiXinPreOrder("1111111", "222"); System.out.println(re+" "+ client.socket.hashCode()); } catch (Exception e) { e.printStackTrace(); }finally{ ConnectionManager.returnThriftConnetion(client); } } }).start(); } catch (Exception e) { e.printStackTrace(); } }
}
这只是一个最简单的pool使用实例,可以做很多的改进,如优化pool中对象,加入动态代理以屏蔽client其他接口。此实例尽起抛砖引玉!
参考资料:
1. apache commons-pool的配置参数 http://www.thinksaas.cn/group/topic/96620/