Apache Thrift本身没有提供连接池,我们可以用Apache Commons Pool来实现一个,Apache commons-pool本质上是"对象池",即通过一定的规则来维护对象集合的容器;commos-pool在很多场景中,用来实现连接池/任务worker池等,大家常用的dbcp数据库连接池,也是基于commons-pool实现的。TCP连接池里的是Socket对象,那么对于thirft连接池里的就是TTransport对象了。
参考了这篇文章:http://www.open-open.com/lib/view/open1415453575730.html,但上官网http://commons.apache.org/proper/commons-pool/download_pool.cgi下载jar时,发现官网上的例子的用法和上面那篇文章的例子的用法有点出入,才发现现在最新版是2.4.2,是重构过的,连包名pool都改成了pool2,不向下兼容的。官网poo2的例子:http://commons.apache.org/proper/commons-pool/examples.html。
据说poo2显著的提升了性能和可伸缩性,特别是在高并发加载的情况下。2.0 版本包含可靠的实例跟踪和池监控,要求 JDK 1.6 或者更新版本。poo2使用了泛型,不用再把object强制转换为你的对象类型了。
简单使用时主要涉及几个类:
GenericObjectPool:对象池类,可以获取和归还一个对象PooledObject等;
BasePooledObjectFactory:对象池GenericObjectPool里管理的对象的工厂类,池可以通过此工厂类创建和销毁一个对象PooledObject等;
GenericObjectPoolConfig:对象池GenericObjectPool的配置类,例如最大连接数,最大和最小空闲连接数等;
查看GenericObjectPool的构造方法,刚好两个参数分别是BasePooledObjectFactory和GenericObjectPoolConfig,而BasePooledObjectFactory是需要我们继承来实现相应的方法的,简单点实现两个抽象方法create和wrap即可,而wrap用默认实现new一个DefaultPooledObject就可以了。所以其实我们只需要实现create方法就行了。
有没有发现poo1是通过实现makeObject方法来创建池对象的,而poo2是create方法,同时poo2也有一个
makeObject方法,好像有点多余或者矛盾,我们查看poo2的BasePooledObjectFactory的源码发现其实poo2也是通过makeObject来创建一个池对象的,只不过里面依次调用了create和wrap,create了一个你的对象后,再把这个对象wrap成池管理类型的对象PooledObject。
源码:org.apache.commons.pool2.BasePooledObjectFactory-》makeObject:
package org.apache.commons.pool2; public abstract class BasePooledObjectFactory<T> implements PooledObjectFactory<T> { public abstract T create() throws Exception; public abstract PooledObject<T> wrap(T obj); @Override public PooledObject<T> makeObject() throws Exception { return wrap(create()); } @Override public void destroyObject(PooledObject<T> p) throws Exception { } @Override public boolean validateObject(PooledObject<T> p) { return true; } @Override public void activateObject(PooledObject<T> p) throws Exception { } @Override public void passivateObject(PooledObject<T> p) throws Exception { } }
关门,放代码:
连接池工厂类ConnectionPoolFactory.java:
import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.thrift.transport.TFastFramedTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; public class ConnectionPoolFactory { private GenericObjectPool<TTransport> pool; public ConnectionPoolFactory(GenericObjectPoolConfig config, String ip, int port) { ConnectionFactory objFactory = new ConnectionFactory(ip, port, 3000); pool = new GenericObjectPool<TTransport>(objFactory, config); } //从池里获取一个Transport对象 public TTransport getConnection() throws Exception { return pool.borrowObject(); } //把一个Transport对象归还到池里 public void releaseConnection(TTransport transport) { pool.returnObject(transport); } /* * 连接池管理的对象Transport的工厂类, * GenericObjectPool会使用此类的create方法来 * 创建Transport对象并放进pool里进行管理等操作。 */ class ConnectionFactory extends BasePooledObjectFactory<TTransport> { private String ip; private int port; private int socketTimeout; public ConnectionFactory(String ip, int port, int socketTimeout) { this.ip = ip; this.port = port; this.socketTimeout = socketTimeout; } //创建TTransport类型对象方法 @Override public TTransport create() throws Exception { TSocket socket = new TSocket(ip, port); socket.setTimeout(socketTimeout); TTransport transport = socket; transport = new TFastFramedTransport(transport); if ( !transport.isOpen() ) { transport.open(); } return transport; } //把TTransport对象打包成池管理的对象PooledObject<TTransport> @Override public PooledObject<TTransport> wrap(TTransport transport) { return new DefaultPooledObject<TTransport>(transport); } } }
使用连接池的客户端类TestPoolClient.java:
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TTransport; import thrift.test.ThriftTest; import thrift.test.User; public class TestPoolClient { public static void main(String [] args) throws Exception { GenericObjectPoolConfig config = new GenericObjectPoolConfig(); //链接池中最大连接数,默认为8 config.setMaxTotal(2); //当连接池资源耗尽时,调用者最大阻塞的时间,超时将跑出异常。单位:毫秒;默认为-1,表示永不超时 config.setMaxWaitMillis(3000); ConnectionPoolFactory poolFactory = new ConnectionPoolFactory(config, "127.0.0.1", 9090); //从连接池取得指定的通信方式 TTransport transport = poolFactory.getConnection(); //指定的通信协议 TProtocol tProtocol = new TCompactProtocol(transport); //ThriftTest.Client是生成的客户端代码 ThriftTest.Client testClient = new ThriftTest.Client(tProtocol); //getUser就是ThriftTest.thrift所定义的接口 User user = testClient.getUser(2); System.out.println("名字:"+ user.getName()); //归还transport到连接池 poolFactory.releaseConnection(transport); } }
运行TestServer.java,再运行TestPoolClient.java,结果:
(服务端打印)Starting the server on port 9090...
(客户端打印)名字:另外一个烟火
工程结构图:
附近src.rar是源码,感谢阅读!!!