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/
