实现Thrift客户端连接池
提到池一般做过Java开发的肯定会想到ObjectPool,Apache Commons项目确实给我们的开发得来了很大的便利性,其中的pool项目正是我们实现thrift连接池的基础,当然也离不了spring。
1、在工程中添加连接池依赖jar包:
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
2、创建服务端服务提供者实现
package com.thrift.server;
import com.service.demo.Hello;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 服务端服务提供者
*/
public class UserServiceServer {
/** 服务的端口 */
private int servicePort;
@Autowired
private Hello.Iface iface;
public void start() {
try {
TServerSocket serverTransport = new TServerSocket(servicePort);
// 关联处理器与 服务的实现
TProcessor processor = new Hello.Processor<Hello.Iface>(iface);
// TBinaryProtocol 二进制编码格式进行数据传输
// 设置协议工厂为 TBinaryProtocol.Factory
TBinaryProtocol.Factory proFactory = new TBinaryProtocol.Factory(true, true);
TThreadPoolServer.Args args = new TThreadPoolServer.Args(serverTransport);
args.processor(processor);
args.protocolFactory(proFactory);
// 多线程服务器端使用标准的阻塞式 I/O
TServer server = new TThreadPoolServer(args);
System.out.println("Starting server on port " + servicePort + "......");
server.serve();
} catch (Exception e) {
e.printStackTrace();
}
}
public int getServicePort() {
return servicePort;
}
public void setServicePort(int servicePort) {
this.servicePort = servicePort;
}
}
3、配置server spring,applicationContext-server.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.thrift.*"/>
<context:component-scan base-package="com.service.*"/>
<!-- 服务端接口配置 -->
<bean id="userServiceServer" class="com.thrift.server.UserServiceServer">
<property name="servicePort" value="7911" />
</bean>
<bean id="helloWorldImpl" class="com.service.demo.impl.HelloServiceImpl"/>
</beans>
4、创建服务端启动类
package com.thriftServer;
import com.thrift.server.UserServiceServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by ssjk on 2016/10/21.
*/
public class PoolServerTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-server.xml");
UserServiceServer userServiceServer = (UserServiceServer) context.getBean("userServiceServer");
userServiceServer.start();
}
}
5、创建连接池实现实现工厂
(1)创建ThriftPoolableObjectFactory.java
package com.thrift.pool;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by ssjk on 2016/10/21.
*/
public class ThriftPoolableObjectFactory implements PoolableObjectFactory<TTransport> {
private final Logger logger = LoggerFactory.getLogger(getClass());
/** 服务的IP */
private String serviceIP;
/** 服务的端口 */
private int servicePort;
/** 超时设置 */
private int timeOut;
public ThriftPoolableObjectFactory(String serviceIP, int servicePort, int timeOut) {
super();
this.serviceIP = serviceIP;
this.servicePort = servicePort;
this.timeOut = timeOut;
}
public TTransport makeObject() throws Exception {
try {
TTransport transport = new TSocket(this.serviceIP, this.servicePort, this.timeOut);
transport.open();
return transport;
} catch (Exception e) {
logger.error("error ThriftPoolableObjectFactory()", e);
throw new RuntimeException(e);
}
}
/**
* 销毁对象
*/
public void destroyObject(TTransport tTransport) throws Exception {
if (tTransport.isOpen()) {
tTransport.close();
}
}
/**
* 检验对象是否可以由pool安全返回
*/
public boolean validateObject(TTransport tTransport) {
try {
if (tTransport instanceof TSocket) {
TSocket thriftSocket = (TSocket) tTransport;
if (thriftSocket.isOpen()) {
return true;
} else {
return false;
}
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
/**
* 激活对象
*/
public void activateObject(TTransport tTransport) throws Exception {
}
/**
* 使无效 以备后用
*/
public void passivateObject(TTransport tTransport) throws Exception {
}
}
(2)创建连接池接口和实现类
连接池接口
package com.thrift.iface;
import org.apache.thrift.transport.TSocket;
/**
* 连接池接口
*/
public interface ConnectionProvider {
/**
* 取链接池中的一个链接
* @return TSocket
*/
TSocket getConnection();
/**
* 返回链接
* @param socket
*/
void returnCon(TSocket socket);
}
连接池接口实现类:ConnectionProviderImpl.java
package com.thrift.ifaceImp;
import com.thrift.iface.ConnectionProvider;
import com.thrift.pool.ThriftPoolableObjectFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Repository;
/**
* 连接池实现
*/
@Repository
public class ConnectionProviderImpl implements ConnectionProvider, InitializingBean, DisposableBean {
/** 服务的IP地址 */
private String serviceIP;
/** 服务的端口 */
private int servicePort;
/** 连接超时配置 */
private int conTimeOut;
/** 可以从缓存池中分配对象的最大数量 */
private int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
/** 缓存池中最大空闲对象数量 */
private int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
/** 缓存池中最小空闲对象数量 */
private int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
/** 阻塞的最大数量 */
private long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
/** 从缓存池中分配对象,是否执行PoolableObjectFactory.validateObject方法 */
private boolean testOnBorrow = GenericObjectPool.DEFAULT_TEST_ON_BORROW;
private boolean testOnReturn = GenericObjectPool.DEFAULT_TEST_ON_RETURN;
private boolean testWhileIdle = GenericObjectPool.DEFAULT_TEST_WHILE_IDLE;
/** 对象缓存池 */
private ObjectPool<TTransport> objectPool = null;
public TSocket getConnection() {
try {
// 从对象池取对象
TSocket socket = (TSocket) objectPool.borrowObject();
return socket;
} catch (Exception e) {
throw new RuntimeException("error getConnection()", e);
}
}
public void returnCon(TSocket socket) {
try {
// 将对象放回对象池
objectPool.returnObject(socket);
} catch (Exception e) {
throw new RuntimeException("error returnCon()", e);
}
}
public void destroy() throws Exception {
try {
objectPool.close();
} catch (Exception e) {
throw new RuntimeException("erorr destroy()", e);
}
}
public void afterPropertiesSet() throws Exception {
// 对象池
objectPool = new GenericObjectPool<TTransport>();
//
((GenericObjectPool<TTransport>) objectPool).setMaxActive(maxActive);
((GenericObjectPool<TTransport>) objectPool).setMaxIdle(maxIdle);
((GenericObjectPool<TTransport>) objectPool).setMinIdle(minIdle);
((GenericObjectPool<TTransport>) objectPool).setMaxWait(maxWait);
((GenericObjectPool<TTransport>) objectPool).setTestOnBorrow(testOnBorrow);
((GenericObjectPool<TTransport>) objectPool).setTestOnReturn(testOnReturn);
((GenericObjectPool<TTransport>) objectPool).setTestWhileIdle(testWhileIdle);
((GenericObjectPool<TTransport>) objectPool).setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
// 设置factory
ThriftPoolableObjectFactory thriftPoolableObjectFactory = new ThriftPoolableObjectFactory(serviceIP, servicePort, conTimeOut);
objectPool.setFactory(thriftPoolableObjectFactory);
}
public String getServiceIP() {
return serviceIP;
}
public void setServiceIP(String serviceIP) {
this.serviceIP = serviceIP;
}
public int getServicePort() {
return servicePort;
}
public void setServicePort(int servicePort) {
this.servicePort = servicePort;
}
public int getConTimeOut() {
return conTimeOut;
}
public void setConTimeOut(int conTimeOut) {
this.conTimeOut = conTimeOut;
}
public int getMaxActive() {
return maxActive;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public int getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public int getMinIdle() {
return minIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public long getMaxWait() {
return maxWait;
}
public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
}
public boolean isTestOnBorrow() {
return testOnBorrow;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public boolean isTestOnReturn() {
return testOnReturn;
}
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public boolean isTestWhileIdle() {
return testWhileIdle;
}
public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}
public ObjectPool<TTransport> getObjectPool() {
return objectPool;
}
public void setObjectPool(ObjectPool<TTransport> objectPool) {
this.objectPool = objectPool;
}
}
6、创建连接池管理类
package com.thrift.controller;
import com.thrift.iface.ConnectionProvider;
import org.apache.thrift.transport.TSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 连接池管理
*/
@Service
public class ConnectionManager {
/** 日志记录器 */
private final Logger logger = LoggerFactory.getLogger(getClass());
/** 保存local对象 */
ThreadLocal<TSocket> socketThreadSafe = new ThreadLocal<TSocket>();
/** 连接提供池 */
@Autowired(required=true)
private ConnectionProvider connectionProvider;
public ConnectionProvider getConnectionProvider() {
return connectionProvider;
}
public void setConnectionProvider(ConnectionProvider connectionProvider) {
this.connectionProvider = connectionProvider;
}
public TSocket getSocket() {
TSocket socket = null;
try {
socket = connectionProvider.getConnection();
socketThreadSafe.set(socket);
return socketThreadSafe.get();
} catch (Exception e) {
logger.error("error ConnectionManager.invoke()", e);
} finally {
connectionProvider.returnCon(socket);
socketThreadSafe.remove();
}
return socket;
}
}
7、创建客户端实现类
package com.thrift.client;
import com.service.demo.Hello;
import com.thrift.controller.ConnectionManager;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TTransportException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Created by ssjk on 2016/10/21.
*/
@Service
public class UserServiceClient {
@Autowired
private ConnectionManager connectionManager;
public void invoke() {
try {
TProtocol protocol = new TBinaryProtocol(connectionManager.getSocket());
Hello.Client client = new Hello.Client(protocol);
System.out.println(client.helloString("连接池测试"));
}catch (Exception e){
e.printStackTrace();
}
}
}
8、客户端spring配置,applicationContext-client.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<description>thrift配置文件 </description>
<context:component-scan base-package="com.thrift.*" />
<!-- 连接池配置 -->
<bean id="connectionProvider" class="com.thrift.ifaceImp.ConnectionProviderImpl">
<property name="serviceIP" value="127.0.0.1" />
<property name="servicePort" value="7911" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="10" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="conTimeOut" value="2000" />
</bean>
</beans>
9、创建客户端启动类
package com.thriftClient;
import com.thrift.client.UserServiceClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by ssjk on 2016/10/21.
*/
public class PoolClientTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-client.xml");
UserServiceClient userServiceClient = (UserServiceClient) context.getBean(UserServiceClient.class);
userServiceClient.invoke();
}
}
10、最后启动服务端PoolServerTest.java 然后启动客户端PoolClientest.java调用
参考资料:
http://blog.csdn.net/column/details/slimina-thrift.html