实现Thrift客户端连接池

提到池一般做过Java开发的肯定会想到ObjectPool,Apache Commons项目确实给我们的开发得来了很大的便利性,其中的pool项目正是我们实现thrift连接池的基础,当然也离不了spring。

在工程中添加依赖jar包:

<dependency>
			<groupId>org.apache.thrift</groupId>
			<artifactId>libthrift</artifactId>
			<version>0.9.2</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.5.8</version>
		</dependency>
		<dependency>
			<groupId>commons-pool</groupId>
			<artifactId>commons-pool</artifactId>
			<version>1.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.0.9.RELEASE</version>
		</dependency>

  • 服务端实现

1.定义thrift服务接口描述

UserService.thrift

namespace java cn.slimsmart.thrift.demo.pool
struct UserRequest
{
	1:string id
}
struct UserResponse
{
	1:string code
	2:map<string,String> params
}
service UserService
{
	UserResponse userInfo(1:UserRequest request)
}
2.使用thrift服务接口描述生成java接口及对象类

使用命令:thrift-0.9.2.exe -r -gen java ./UserService.thrift 生成java接口及对象,并将生成的java类复制到java工程。

cd gen-java\cn\slimsmart\thrift\demo\pool

UserRequest.java

UserResponse.java

UserService.java

3.服务接口实现类

UserServiceImpl.java

package cn.slimsmart.thrift.demo.pool;

import java.util.HashMap;
import java.util.Map;

import org.apache.thrift.TException;
import org.springframework.stereotype.Service;

/**
 *  业务接口实现
 */
@Service
public class UserServiceImpl implements UserService.Iface{

	@Override
	public UserResponse userInfo(UserRequest request) throws TException {
		try{
			UserResponse urp=new UserResponse();
			if(request.id.equals("10000")){
				urp.setCode("0");
				Map<String,String> params= new HashMap<String,String>();
				params.put("name", "lucy");
				urp.setParams(params);
			}
			System.out.println("接收参数是:id="+request.id);
			return urp;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}

}

4.服务端服务提供者实现

UserServiceServer.java

package cn.slimsmart.thrift.demo.pool;

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 UserService.Iface iface;

	public void start() {
		try {
			TServerSocket serverTransport = new TServerSocket(servicePort);
			// 关联处理器与 服务的实现
			TProcessor processor = new UserService.Processor<UserService.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;
	}
}
5.配置server spring,pool/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"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
				http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"
	default-lazy-init="true">
	<description>thrift配置文件 </description>
	<context:component-scan base-package="cn.slimsmart.thrift.demo.pool" />
	<!-- 服务端接口配置 -->
	<bean id="userServiceServer" class="cn.slimsmart.thrift.demo.pool.UserServiceServer">
		<property name="servicePort" value="8080" />
	</bean>
</beans>

6.服务端启动类

ServerTest.java

package cn.slimsmart.thrift.demo.pool;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ServerTest {

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:pool/applicationContext-server.xml");
		UserServiceServer userServiceServer = (UserServiceServer) context.getBean(UserServiceServer.class);
		userServiceServer.start();
	}
}

  • 连接池实现
1.连接工厂实现
ThriftPoolableObjectFactory.java
package cn.slimsmart.thrift.demo.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;

/**
 * 连接池工厂
 */
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;
	}

	/**
	 * 激活对象
	 */
	@Override
	public void activateObject(TTransport tTransport) throws Exception {
	}

	/**
	 * 销毁对象
	 */
	@Override
	public void destroyObject(TTransport tTransport) throws Exception {
		if (tTransport.isOpen()) {
			tTransport.close();
		}
	}

	/**
	 * 创建对象
	 */
	@Override
	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);
		}
	}

	/**
	 * 使无效 以备后用
	 */
	@Override
	public void passivateObject(TTransport tTransport) throws Exception {
	}

	/**
	 * 检验对象是否可以由pool安全返回
	 */
	@Override
	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;
		}
	}
}
2.连接池实现
连接池接口:ConnectionProvider.java
package cn.slimsmart.thrift.demo.pool;

import org.apache.thrift.transport.TSocket;

/**
 * 连接池接口
 *
 */
public interface ConnectionProvider {
	/**
	* 取链接池中的一个链接
	* @return TSocket
	*/
	TSocket getConnection();
	
	/**
	* 返回链接
	* @param socket
	*/
	void returnCon(TSocket socket);
}
连接池接口实现:ConnectionProviderImpl.java
package cn.slimsmart.thrift.demo.pool;

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;

/**
 * 连接池实现
 */
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;

	@Override
	public TSocket getConnection() {
		try {
			// 从对象池取对象
			TSocket socket = (TSocket) objectPool.borrowObject();
			return socket;
		} catch (Exception e) {
			throw new RuntimeException("error getConnection()", e);
		}
	}

	@Override
	public void returnCon(TSocket socket) {
		try {
			// 将对象放回对象池
			objectPool.returnObject(socket);
		} catch (Exception e) {
			throw new RuntimeException("error returnCon()", e);
		}
	}

	@Override
	public void destroy() throws Exception {
		try {
			objectPool.close();
		} catch (Exception e) {
			throw new RuntimeException("erorr destroy()", e);
		}
	}

	@SuppressWarnings("deprecation")
	@Override
	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;
	}
}
3.连接池管理
ConnectionManager.java
package cn.slimsmart.thrift.demo.pool;

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
	private 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;
	}

}
  • 客户端实现
1.客户端调用实现
UserServiceClient.java
package cn.slimsmart.thrift.demo.pool;

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;

/**
 * 服务客户端调用
 */
@Service
public class UserServiceClient {

	@Autowired
	private ConnectionManager connectionManager;

	public void invoke() {
		try {
			TProtocol protocol = new TBinaryProtocol(connectionManager.getSocket());
			UserService.Client client = new UserService.Client(protocol);
			UserRequest request = new UserRequest();
			request.setId("10000");
			UserResponse urp = client.userInfo(request);
			if (urp.code != null && !urp.code.equals("")) {
				System.out.println("返回代码:" + urp.code + "; 参数是:" + urp.params.get("name"));
			}
		} catch (TTransportException e) {
			e.printStackTrace();
		} catch (TException e) {
			e.printStackTrace();
		}
	}
}
2.客户端spring配置,pool/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"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
				http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"
	default-lazy-init="true">
	<description>thrift配置文件 </description>
	<context:component-scan base-package="cn.slimsmart.thrift.demo.pool" />
	<!-- 连接池配置 -->
	<bean id="connectionProvider" class="cn.slimsmart.thrift.demo.pool.ConnectionProviderImpl">
		<property name="serviceIP" value="127.0.0.1" />
		<property name="servicePort" value="8080" />
		<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>
3.客户端启动类
ClientTest.java
package cn.slimsmart.thrift.demo.pool;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ClientTest {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:pool/applicationContext-client.xml");
		UserServiceClient userServiceClient = (UserServiceClient) context.getBean(UserServiceClient.class);
		userServiceClient.invoke();
	}
}
启动ServerTest.java,在运行客户端测试ClientTest.java。

你可能感兴趣的:(thrift,连接池,rpc)