提到池一般做过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(); } }
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; } } }
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); }
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; } }
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; } }
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(); } } }
<?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>
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。