用apache commons-pool2建立thrift连接池

  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/    

posted on 2015-12-14 15:52  loveoobaby  阅读(2240)  评论(0编辑  收藏  举报

导航