由浅入深了解Thrift之客户端连接池化续
前文《由浅入深了解Thrift之客户端连接池化》中我们已经实现了服务调用端 连接的池化,实现的过于简陋,离实际的项目运用还很遥远。本文将在进一步改造,主要是两方面:1、服务端如何注册多个服务 2、调用端如何获取服务对象而不是服务连接
一、实现思路
1、通过spring配置文件,配置服务类
2、反射生成服务类实例,依次注册服务
调用端获取服务对象亦是如此,废话不多说了
二、主要实现
1、服务端
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * thrift server端,向zk中注册server address * * @author wy * */ public class ThriftServiceServerFactory implements InitializingBean { private final Logger logger = LoggerFactory.getLogger(getClass()); // thrift server 服务端口 private Integer port; // default 权重 private Integer priority = 1; // service 实现类 private Map<String, Object> services; // thrift server 注册路径 private String configPath; // thrift service module private String configService; private ThriftServerIpTransfer ipTransfer; // thrift server注册类 private ThriftServerAddressReporter addressReporter; // thrift server开启服务 private ServerThread serverThread; @Override public void afterPropertiesSet() throws Exception { if (ipTransfer == null) { ipTransfer = new LocalNetworkIpTransfer(); } String ip = ipTransfer.getIp(); if (ip == null) { throw new NullPointerException("cant find server ip..."); } String hostName = ip + ":" + port + ":" + priority; logger.info("registry services address = " + hostName); logger.info("registry services count = " + services.size()); Set<Entry<String, Object>> set = services.entrySet(); Iterator<Entry<String, Object>> iter = set.iterator(); Map<String, TProcessor> processors = new HashMap<String, TProcessor>(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); for (; iter.hasNext();) { Entry<String, Object> entry = iter.next(); // 通过反射获取service interface String servieName = entry.getKey(); Object serviceImplObject = entry.getValue(); Class<?> serviceClass = serviceImplObject.getClass(); // 返回本类直接实现的接口.不包含泛型参数信息 Class<?>[] interfaces = serviceClass.getInterfaces(); if (interfaces.length == 0) { throw new IllegalClassFormatException("service-class should implements Iface"); } TProcessor processor = null; for (Class<?> interfaceClazz : interfaces) { logger.info("service Interfaces count = " + interfaces.length); // 获取源代码中给出的'底层类'简称 String cname = interfaceClazz.getSimpleName(); if (!cname.equals("Iface")) { continue; } // 获取外部类Class;以String的形式,返回Class对象的'实体'名称 String pname = interfaceClazz.getEnclosingClass().getName() + "$Processor"; Class<?> pclass = classLoader.loadClass(pname); // class是否相同或是另一个类的超类或接口 if (!pclass.isAssignableFrom(Processor.class)) { continue; } Constructor<?> constructor = pclass.getConstructor(interfaceClazz); processor = (TProcessor) constructor.newInstance(serviceImplObject); processors.put(servieName, processor); break; } if (processor == null) { throw new IllegalClassFormatException("service-class should implements Iface"); } } // 需要单独的线程,因为serve方法是阻塞的. serverThread = new ServerThread(processors, port); serverThread.start(); // 向ZK中注册服务 if (addressReporter != null) { addressReporter.report(configPath, hostName); } } class ServerThread extends Thread { private TServer server; ServerThread(Map<String, TProcessor> processors, int port) throws Exception { // 设置传输通道 TNonblockingServerSocket serverTransport = new TNonblockingServerSocket( port); // 设置二进制协议 Factory protocolFactory = new TBinaryProtocol.Factory(); // 网络服务模型 TThreadedSelectorServer.Args tssArgs = new TThreadedSelectorServer.Args( serverTransport); // TMultiplexedProcessor processor = new TMultiplexedProcessor(); Set<Entry<String, TProcessor>> set = processors.entrySet(); Iterator<Entry<String, TProcessor>> iter = set.iterator(); // for (; iter.hasNext();) { Entry<String, TProcessor> entry = iter.next(); processor.registerProcessor(entry.getKey(), (TProcessor) entry.getValue()); tssArgs.processor(processor); } tssArgs.protocolFactory(protocolFactory); // tssArgs.transportFactory(new TFramedTransport.Factory()); int num = Runtime.getRuntime().availableProcessors() * 2 + 1; tssArgs.selectorThreads(num); tssArgs.workerThreads(num * 10); server = new TThreadedSelectorServer(tssArgs); } @Override public void run() { try { server.serve(); } catch (Exception e) { e.printStackTrace(); } } // 关闭thrift server public void stopServer() { if (server != null && !server.isServing()) { server.stop(); } } } // 关闭thrift server public void close() { serverThread.stopServer(); } public void setServices(Map<String, Object> services) { this.services = services; } public void setPriority(Integer priority) { this.priority = priority; } public void setPort(Integer port) { this.port = port; } public void setIpTransfer(ThriftServerIpTransfer ipTransfer) { this.ipTransfer = ipTransfer; } public void setAddressReporter(ThriftServerAddressReporter addressReporter) { this.addressReporter = addressReporter; } public void setConfigPath(String configPath) { this.configPath = configPath; } public String getConfigService() { return configService; } public void setConfigService(String configService) { this.configService = configService; } }
spring配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!-- zookeeper --> <bean id="thriftZookeeper" class="com.wy.thriftpool.commzkpool.zookeeper.ZookeeperFactory" destroy-method="close"> <property name="connectString" value="127.0.0.1:2181" /> <property name="namespace" value="thrift/thrift-service" /> </bean> <bean id="serviceAddressReporter" class="com.wy.thriftpool.commzkpool.support.impl.DynamicAddressReporter" destroy-method="close"> <property name="zookeeper" ref="thriftZookeeper" /> </bean> <bean id="userService" class="com.wy.thrift.service.UserServiceImpl"/> <bean class="com.wy.thriftpool.commzkpool.server.ThriftServiceServerFactory" destroy-method="close"> <property name="configPath" value="serviceAddress" /> <property name="configService" value="serviceModule" /> <property name="port" value="9090" /> <property name="addressReporter" ref="serviceAddressReporter" /> <property name="services"> <map> <entry key="userService" value-ref="userService" /> </map> </property> </bean>
2、调用端
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * TServiceClient,工厂类 * thrift Client端负责于thrift server通信 * * @author wy */ public class AbstractThriftServiceClientFactory extends BasePoolableObjectFactory<TServiceClient> { private final Logger logger = LoggerFactory.getLogger(getClass()); // 超时设置 private int timeOut; private final ThriftServerAddressProvider addressProvider; private final TServiceClientFactory<TServiceClient> clientFactory; private PoolOperationCallBack callback; protected AbstractThriftServiceClientFactory( ThriftServerAddressProvider addressProvider, TServiceClientFactory<TServiceClient> clientFactory) throws Exception { this.addressProvider = addressProvider; this.clientFactory = clientFactory; } protected AbstractThriftServiceClientFactory( ThriftServerAddressProvider addressProvider, TServiceClientFactory<TServiceClient> clientFactory, PoolOperationCallBack callback) throws Exception { this.addressProvider = addressProvider; this.clientFactory = clientFactory; this.callback = callback; } protected AbstractThriftServiceClientFactory( ThriftServerAddressProvider addressProvider, TServiceClientFactory<TServiceClient> clientFactory, PoolOperationCallBack callback, int timeOut) throws Exception { this.addressProvider = addressProvider; this.clientFactory = clientFactory; this.callback = callback; this.timeOut = timeOut; } /** * 创建对象 */ @Override public TServiceClient makeObject() throws Exception { InetSocketAddress address = addressProvider.selector(); logger.info("server address=" + address.getHostName() + ":" + address.getPort()); TSocket tsocket = new TSocket(address.getHostName(), address.getPort(), this.timeOut); TProtocol protocol = new TBinaryProtocol(tsocket); TServiceClient client = this.clientFactory.getClient(protocol); tsocket.open(); if (callback != null) { callback.make(client); } return client; } /** * 销毁对象 */ public void destroyObject(TServiceClient client) throws Exception { if (callback != null) { callback.destroy(client); try { TTransport transport = client.getInputProtocol().getTransport(); if (transport.isOpen()) { transport.close(); } } catch (Exception e) { e.printStackTrace(); } } } /** * 检验对象是否可以由pool安全返回 */ public boolean validateObject(TServiceClient client) { try { TTransport transport = client.getInputProtocol().getTransport(); if (transport.isOpen()) { return true; } else { return false; } } catch (Exception e) { return false; } } public static interface PoolOperationCallBack { // 创建成功前执行 void make(TServiceClient client); // 销毁client之前执行 void destroy(TServiceClient client); } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 服务调用方使用 * * @author wy * */ public class ThriftServiceClientProxyFactory implements FactoryBean<Object>, InitializingBean { private final Logger logger = LoggerFactory.getLogger(getClass()); // 最大活跃连接数 private Integer maxActive = 32; // 最小空闲对象数量 private Integer minIdle =1; // 链接空闲时间default 3 private Integer idleTime = 1000 * 60 * 3; // 连接超时配置 private int conTimeOut = 1000 * 2; // private boolean testOnBorrow = true; // private boolean testOnReturn = true; // private boolean testWhileIdle = true; // 具体的服务接口类 private String service; // fixed server address provider private String serverAddress; // dynamic server address provider private ThriftServerAddressProvider addressProvider; // 对象缓存池 private GenericObjectPool<TServiceClient> pool; // 服务实例 private Object proxyClient; // 服务接口类Iface private Class<?> objectClass; @Override public void afterPropertiesSet() throws Exception { logger.info("init objectPool..."); if (serverAddress != null) { logger.info("FixedAddressProvider..."); addressProvider = new FixedAddressProvider(serverAddress); } else { logger.info("DynamicAddressProvider..."); } ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 加载Iface接口 objectClass = classLoader.loadClass(service + "$Iface"); // 加载Client.Factory类 Class<TServiceClientFactory<TServiceClient>> clazz = (Class<TServiceClientFactory<TServiceClient>>) classLoader.loadClass(service + "$Client$Factory"); TServiceClientFactory<TServiceClient> clientFactory = clazz.newInstance(); // PoolFactory AbstractThriftServiceClientFactory clientPool = new AbstractThriftServiceClientFactory( addressProvider, clientFactory, callback, conTimeOut); // 对象缓存池 GenericObjectPool.Config poolConfig = new GenericObjectPool.Config(); // 缓存池中分配对象的最大数量 poolConfig.maxActive = maxActive; // 缓存池中最小空闲对象数量 poolConfig.minIdle = minIdle; // poolConfig.minEvictableIdleTimeMillis = idleTime; // poolConfig.timeBetweenEvictionRunsMillis = idleTime / 2L; // poolConfig.testOnBorrow = testOnBorrow; // poolConfig.testOnReturn = testOnReturn; // poolConfig.testWhileIdle = testWhileIdle; pool = new GenericObjectPool<TServiceClient>(clientPool, poolConfig); // 反射,服务实例 proxyClient = Proxy.newProxyInstance(classLoader, new Class[] { objectClass }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 从对象池取对象 TServiceClient client = pool.borrowObject(); try { return method.invoke(client, args); } catch (Exception e) { throw e; } finally { // 将对象放回对象池 pool.returnObject(client); } } }); } /** * 获取服务实例,并已归还池中对象 */ @Override public Object getObject() throws Exception { return proxyClient; } /** * 销毁对象池 * * @throws Exception */ public void destroyObject() throws Exception { try { pool.close(); } catch (Exception e) { throw new RuntimeException("erorr destroy()", e); } } /** * 关闭server address provider */ public void close() { if (addressProvider != null) { addressProvider.close(); } } @Override public boolean isSingleton() { // To change body of implemented methods use File | Settings | File Templates. return true; } @Override public Class<?> getObjectType() { return objectClass; } PoolOperationCallBack callback = new PoolOperationCallBack() { @Override public void make(TServiceClient client) { logger.info("create proxyClient..."); } @Override public void destroy(TServiceClient client) { logger.info("destroy proxyClient..."); } }; public void setMaxActive(Integer maxActive) { this.maxActive = maxActive; } public void setIdleTime(Integer idleTime) { this.idleTime = idleTime; } public void setService(String service) { this.service = service; } public void setServerAddress(String serverAddress) { this.serverAddress = serverAddress; } public void setAddressProvider(ThriftServerAddressProvider addressProvider) { this.addressProvider = addressProvider; } public int getConTimeOut() { return conTimeOut; } public void setConTimeOut(int conTimeOut) { this.conTimeOut = conTimeOut; } public Integer getMaxActive() { return maxActive; } public Integer getIdleTime() { return idleTime; } 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; } }
spring配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!-- zookeeper --> <bean id="thriftZookeeper" class="com.wy.thriftpool.commzkpool.zookeeper.ZookeeperFactory" destroy-method="close"> <property name="connectString" value="127.0.0.1:2181" /> <property name="namespace" value="thrift/thrift-service" /> </bean> <bean id="userService" class="com.wy.thriftpool.commzkpool.client.ThriftServiceClientProxyFactory" destroy-method="close"> <property name="maxActive" value="5" /> <property name="idleTime" value="1800000" /> <property name="addressProvider"> <bean class="com.wy.thriftpool.commzkpool.support.impl.DynamicAddressProvider"> <property name="configPath" value="serviceAddress" /> <property name="zookeeper" ref="thriftZookeeper" /> </bean> </property> <property name="service" value="com.wy.thrift.service.UserService" /> </bean>
由于本人经验有限,文章中难免会有错误,请浏览文章的您指正或有不同的观点共同探讨!
最新文章,请关注微信公众号
![](https://images.cnblogs.com/cnblogs_com/exceptioneye/978972/t_qrcode_for_gh_3c9b028059b0_430.jpg)
作者:三石雨
出处:http://www.cnblogs.com/exceptioneye
再烦,也别忘微笑;再急,也要注意语气。
再苦,也别忘坚持;再累,也要爱自己。
低调做人,你会一次比一次稳健;高调做事,你会一次比一次优秀。
![](https://images.cnblogs.com/cnblogs_com/exceptioneye/978972/t_qrcode_for_gh_3c9b028059b0_430.jpg)
作者:三石雨
出处:http://www.cnblogs.com/exceptioneye
再烦,也别忘微笑;再急,也要注意语气。
再苦,也别忘坚持;再累,也要爱自己。
低调做人,你会一次比一次稳健;高调做事,你会一次比一次优秀。