前文《由浅入深了解Thrift之客户端连接池化》中我们已经实现了服务调用端 连接的池化,实现的过于简陋,离实际的项目运用还很遥远。本文将在进一步改造,主要是两方面:1、服务端如何注册多个服务 2、调用端如何获取服务对象而不是服务连接

一、实现思路

1、通过spring配置文件,配置服务类

2、反射生成服务类实例,依次注册服务

调用端获取服务对象亦是如此,废话不多说了

二、主要实现

1、服务端

/**
* 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配置文件

<!-- 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、调用端

/**
* 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);
} }
/**
* 服务调用方使用
*
* @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配置文件

<!-- 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>

由于本人经验有限,文章中难免会有错误,请浏览文章的您指正或有不同的观点共同探讨!

由浅入深了解Thrift之客户端连接池化续的更多相关文章

  1. 由浅入深了解Thrift之客户端连接池化

    一.问题描述 在上一篇<由浅入深了解Thrift之服务模型和序列化机制>文章中,我们已经了解了thrift的基本架构和网络服务模型的优缺点.如今的互联网圈中,RPC服务化的思想如火如荼.我 ...

  2. Redis客户端连接池

    使用场景 对于一些大对象,或者初始化过程较长的可复用的对象,我们如果每次都new对象出来,那么意味着会耗费大量的时间. 我们可以将这些对象缓存起来,当接口调用完毕后,不是销毁对象,当下次使用的时候,直 ...

  3. thrift - C#(CSharp)客户端连接池(ConnectionPool)

      调用示例:   var tran = ThriftPool.Instance().BorrowInstance(); TProtocol protocol = new TBinaryProtoco ...

  4. Swoole2.0协程客户端连接池的实现

    Swoole2.0官方默认的实例是短连接的,在请求处理完毕后就会切断redis或mysql的连接.实际项目可以使用连接池实现复用. 实现原理也很简单,使用SplQueue,在请求到来时判断资源队列中是 ...

  5. 高可用的池化 Thrift Client 实现(源码分享)

    本文将分享一个高可用的池化 Thrift Client 及其源码实现,欢迎阅读源码(Github)并使用,同时欢迎提出宝贵的意见和建议,本人将持续完善. 本文的主要目标读者是对 Thrift 有一定了 ...

  6. 由浅入深了解Thrift之服务模型和序列化机制

    一.Thrift介绍 Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎.其允许你定义一个简单的定义文件中的数据类型和服务接口.以作为输入文件,编 ...

  7. 一个I/O线程可以并发处理N个客户端连接和读写操作 I/O复用模型 基于Buf操作NIO可以读取任意位置的数据 Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel 事件驱动消息通知观察者模式

    Tomcat那些事儿 https://mp.weixin.qq.com/s?__biz=MzI3MTEwODc5Ng==&mid=2650860016&idx=2&sn=549 ...

  8. redis客户端连接异常

    本文参考:http://mdba.cn/2015/04/02/redistwemproxy-%e5%ae%a2%e6%88%b7%e7%ab%af%e8%bf%9e%e6%8e%a5%e5%bc%82 ...

  9. atitit.客户端连接oracle数据库的方式总结

    客户端连接oracle数据库的方式总结 目录 Java程序连接一般使用jar驱动连接..... 桌面GUI一般采取c语言驱动oci.dll 直接连接... 间接连接(需要配置tns及其envi var ...

随机推荐

  1. python学习应用笔记(一)

    之前一直用c++写程序  所以考虑程序一般都比较容易往数据结构的方向想 而自己设计数据结构往往要费很大事  昨天看了一下python  发现脚本语言 真是厉害    用来进行模拟运算确实不错  可以先 ...

  2. SQL基础篇----select语句与排序问题

    一.检索--输出所有的列 SELECT * FROM my_friends WHEREfirst_name = 'cake'; 知识点1 * 代表选择出所有的行-----(什么行呢?)就是first_ ...

  3. [转]Oracle 10g及pro*c相关问题及解决方法(转)

    Oracle 10g及pro*c相关问题及解决方法 2008年08月21日 星期四 上午 11:21 最近一直在进行ORACLE 10g和PRO*C的学习. 其中遇到了不少的问题: 现列于此,已备他用 ...

  4. java 命令对象简单学习实现:

    命令模式:首先我们要知道命令模式的基本定义:来自客户端的请求传入一个对象,从而使你可用不同的请求对客户进行参数化.用于“行为请求者”与“行为实现者”解耦,可实现二者之间的松耦合,以便适应变化.分离变化 ...

  5. RMAN - "丢失控制文件的恢复"

    OS: Oracle Linux Server release 5.7 DB: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - ...

  6. 最大似然估计(MLE)和最大后验概率(MAP)

    最大似然估计: 最大似然估计提供了一种给定观察数据来评估模型参数的方法,即:“模型已定,参数未知”.简单而言,假设我们要统计全国人口的身高,首先假设这个身高服从服从正态分布,但是该分布的均值与方差未知 ...

  7. JavaScript高级程序设计之EventUtil

    简单的通用事件方法 var EventUtil = { getEvent: function (e) { return e || window.event; }, getTarget: functio ...

  8. mini6410-JNI-led

    一.编写JNI模块 当安装好NDK编译环境后,会在它的目录下找到sample目录,它里面有一些例子,可以参考这些例子来写我们自已的模块. 1.在/home/android/文件夹下,新建“ledjni ...

  9. maven属性

    Maven内置了三大特性:属性.Profile和资源过滤来支持构建的灵活性. 内置属性:主要有两个常用内置属性 ${basedir}表示项目根目录,即包含pom.xml文件的目录 ${version} ...

  10. C++中的const关键字的用法

    1.const用于修饰普通变量,表示常量,不建议修改,某种程度上不允许修改(其实也是可以修改的) 指针常量 :指针(指向的变量的值)自身是一个常量,说明不能改变自身的指向  int* const p= ...