自定义Thrift连接池

自定义Thrift连接池

Thrift作为一个高性能的RPC框架,广泛应用于后端服务的进程间接口调用场景中。对于Java开发者而言,thrift客户端调用框架并没有提供相关的连接池能力进行使用,对于性能要求较高的用户可以自定义Thrift连接池以满足自身的需求,本着不重复造轮子的原则,笔者使用apache commons-pools2实现了一套自定义的Thrift连接池供大家参考。
关于apache commons-pools2的相关知识,大家可以参考这篇博文:http://blog.csdn.net/amon1991/article/details/77110657


1、创建池对象工厂

PooledObjectFactory(池对象工厂)是commons-pools2中的一个概念,用于控制整个池对象的整个生命周期。

在我们的实例中,这个池对象就是TProtocol对象,准确来说,commons-pools2管理的对象其实是TProtocol在池中的封装对象,也就是实例中通过wrap(TProtocol protocol)方法包裹后生成的对象PooledObject,这个封装的对象保有实际被包装对象的复杂的状态信息,这个状态信息在判断对象是否存活,是否可以被销毁时起到了关键作用。下面给出实际的新建Thfift池对象工厂代码,笔者使用的是TMultiplexedProtocol对象,使用其他TProtocol对象的参考这种写法即可。

代码块

public class TProtocolFactory extends BasePooledObjectFactory<TProtocol>{

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final int TIMEOUT = 3000000; // 超时时间
    private static final int MAX_LENGTH = 1638400000; // 单次最大传输的数据量(1.6G)

    public static final String PI_SERVICE = "PiService";
    public static final String OPC_SERVICE = "OpcService";

    private String host;
    private int port;
    private boolean keepAlive = true; // 是否持有Thrift连接,不持有则钝化时释放连接
    private String sourceType; // PI数据源还是OPC数据源


    public TProtocolFactory(String host, int port, boolean keepAlive, String sourceType) {
        this.host = host;
        this.port = port;
        this.keepAlive = keepAlive;
        this.sourceType = sourceType;
    }

    private TProtocolFactory() {
    }

    /**
     * 创建新对象
     * @return
     * @throws Exception
     */
    @Override
    public TProtocol create() throws Exception {

        TSocket tSocket = new TSocket(host, port,TIMEOUT );
        TTransport tTransport = new TFramedTransport(tSocket,MAX_LENGTH);

        if (null!= tTransport && !tTransport.isOpen()){
            tTransport.open();
        }

        TProtocol protocol = new TCompactProtocol(tTransport);

        if (null != sourceType) {

            if (sourceType.equals(PI_SERVICE)){
                return new TMultiplexedProtocol(protocol,PI_SERVICE);
            }else if (sourceType.equals(OPC_SERVICE)){
                return new TMultiplexedProtocol(protocol,OPC_SERVICE);
            }else {
                return  null;
            }

        }else {
            return null;
        }

    }

    /**
     * 将对象放入对象池前先包装对象,好让对象池可以管理
     * @param protocol
     * @return
     */
    @Override
    public PooledObject wrap(TProtocol protocol) {
        return new DefaultPooledObject<>(protocol);
    }

    /**
     * 对象钝化(即:从激活状态转入非激活状态,returnObject时触发)
     * @param pooledObject
     * @throws TTransportException
     */
    @Override
    public void passivateObject(PooledObject pooledObject) throws TTransportException {

        if (null!= pooledObject.getObject()){
            if (!keepAlive) {
                pooledObject.getObject().getTransport().flush();
                pooledObject.getObject().getTransport().close();
            }
        }

    }

    /**
     * 对象激活(borrowObject时触发)
     * @param pooledObject
     * @throws TTransportException
     */
    @Override
    public void activateObject(PooledObject pooledObject) throws TTransportException {

        if (!pooledObject.getObject().getTransport().isOpen()) {
            pooledObject.getObject().getTransport().open();
        }

    }

    /**
     * 对象销毁(clear时会触发)
     * @param pooledObject
     * @throws TTransportException
     */
    @Override
    public void destroyObject(PooledObject pooledObject) throws TTransportException {

        if (null!= pooledObject.getObject()){
            if (pooledObject.getObject().getTransport().isOpen()) {
                pooledObject.getObject().getTransport().flush();
                pooledObject.getObject().getTransport().close();
            }
        }

        pooledObject.markAbandoned();

    }

    /**
     * 验证对象的有效性
     * @param pooledObject
     * @return
     */
    @Override
    public boolean validateObject(PooledObject pooledObject) {

        if (pooledObject.getObject() != null) {
            if (pooledObject.getObject().getTransport().isOpen()) {
                return true;
            }

            try {
                pooledObject.getObject().getTransport().open();
                return true;
            } catch (TTransportException e) {
                logger.error(e.getMessage());
            }
        }

        return false;

    }


}

2、创建对象池实例

Object Pool(对象池)是实际管理所有池对象的容器,主要的方法是borrowObject、returnObject,一个是从池中获取对象,另一个是使用完对象后将对象归还到池中,当然,该容器还提供了一些基本的方法用于获取当前存活的对象数,空闲的对象数等信息,这些信息可用于自定义销毁对象策略等实现。

由于笔者的代码中用到了Spring框架,所以外部代码获取连接池实例使用的是Spring容器管理的单例实例。注意,在对象池的使用上,必须保证对象池是线程安全的,否则可能在多线程环境导致对象池维护的数据产生不一致的问题。假设没有使用Spring框架,笔者推介使用一个饿汉模式的单例来维护pool对象即可。

@Component
public class OPCTProtocolPool {

    @Autowired
    private PiDataSourceConf piDataSource;

    @Autowired
    private ObjectPoolConfig objectPoolConfig;


    private ObjectPool pool;

    /**
     * 获取 thrift 连接对象池
     * @return
     */
    public ObjectPool getPool() {

        if (pool == null){

            GenericObjectPoolConfig poolConfig = objectPoolConfig.getGenericObjectPoolConfig();

            // 第一次加载对象池
            pool = new GenericObjectPool<>(new TProtocolFactory(piDataSource.getIp(), piDataSource.getPort(), true ,TProtocolFactory.OPC_SERVICE), poolConfig);

        }

        return pool;

    }



}

以上代码中,GenericObjectPoolConfig 对象可以设置连接池的参数,比如最大连接数、最大空闲数、超时时间等信息,具体可以参考commons-pools中的通用配置即可。

3、使用对象池使用TProtocol对象

完成上面两步之后,就可以从对象池中非常简单的获取TProtocol对象了,获取对象使用如下代码:

TProtocol protocol = protocolPool.getPool().borrowObject();

使用完对象后,必须使用同一个对象池返回使用的对象,否则这个对象就在进程中失控了:

protocolPool.getPool().returnObject(protocol);

你可能感兴趣的:(java高级编程)