Thrift 使用以及使用动态代理透明化调用
github项目地址:
本文介绍的是多服务的调用与使用动态代理进行透明化调用
因为每次调用方法时都要对transport (io/socket 资源) 进行开启关闭,所以就想设计client 代理起来,然后在前后添加 transport 的open 和 close() (finally);
当然之后在研究自己写一款thrift的连接池,因为io资源不一定每次都需要创建!!!
thrift 版本号 0.10.0
thrift 文件:
IThriftInfoTestService.thrift
IThriftTestService.thrift
IThriftInfoTestService.thrift
代码:
namespace java com.java.thrift.service
namespace cpp com.java.thrift.service
namespace perl com.java.thrift.service
namespace php com.java.thrift.service
service IThriftInfoTestService {
string showInfoData(1:string name,2:bool b2,3:map<string,string> m2)
}
IThriftTestService.thrift
代码:
namespace java com.java.thrift.service
namespace cpp com.java.thrift.service
namespace perl com.java.thrift.service
namespace php com.java.thrift.service
service IThriftTestService {
string showThriftResult(1:string name,2:bool b2,3:map<string,string> m2)
}
provider
spring配置文件 spring-thrift.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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
>
<!-- 两个thrift 服务的实现类 -->
<bean id="thriftInfoTestServiceTarget" class="com.java.core.rpc.thrift.service.impl.ThriftInfoTestServiceImpl" ></bean>
<bean id="thriftTestServiceTarget" class="com.java.core.rpc.thrift.service.impl.ThriftTestServiceImpl" ></bean>
<!-- Processor调用过程工厂,创建多服务类的工厂类 -->
<bean id="thriftProcessorFactory" class="com.java.core.rpc.thrift.supports.ThriftProcessorFactory"
init-method="convertTargetToTProcessor"
>
<property name="targets" >
<list >
<ref bean="thriftInfoTestServiceTarget"/>
<ref bean="thriftTestServiceTarget"/>
</list>
</property>
</bean>
<!-- thrift 的provider的启动类 -->
<bean class="com.java.core.rpc.thrift.provider.AppThriftServer" init-method="initThriftServer" ></bean>
</beans>
ThriftInfoTestServiceImpl.java
package com.java.core.rpc.thrift.service.impl;
import java.util.Map;
import org.apache.thrift.TException;
import com.alibaba.fastjson.JSONObject;
import com.java.core.rpc.thrift.service.IThriftInfoTestService;
public class ThriftInfoTestServiceImpl implements IThriftInfoTestService.Iface {
@Override
public String showInfoData(String name, boolean success, Map<String, String> map) throws TException {
// TODO Auto-generated method stub
System.out.println(" ThriftInfoTestServiceImpl doing ...showInfoData()... ");
System.out.println(" map : "+ JSONObject.toJSONString(map));
System.out.println(" success : "+ success);
System.out.println(" name : "+ name);
String result = name +" time : " + System.currentTimeMillis();
return result;
}
}
ThriftTestServiceImpl.java 代码就不贴了。都一样
ThriftProcessorFactory.java processor工厂类
public class ThriftProcessorFactory {
private final static String IFACE_NAME="$Iface";
private final static String PROCESS_NAME="$Processor";
private List<Object> targets;
private Map<String, TProcessor> processors;
private TMultiplexedProcessor multiplexedProcessor;
public TMultiplexedProcessor getMultiplexedProcessor() {
return multiplexedProcessor;
}
public void setMultiplexedProcessor(TMultiplexedProcessor multiplexedProcessor) {
this.multiplexedProcessor = multiplexedProcessor;
}
public ThriftProcessorFactory() {
super();
// TODO Auto-generated constructor stub
}
public Map<String, TProcessor> getProcessors() {
return processors;
}
public void setProcessors(Map<String, TProcessor> processors) {
this.processors = processors;
}
public List<Object> getTargets() {
return targets;
}
public void setTargets(List<Object> targets) {
this.targets = targets;
}
/**
* 将实现类封装成TProcessor类的集合
*
*/
public void convertTargetToTProcessor(){
if (targets.isEmpty()) {
return ;
}
processors = new HashMap<String, TProcessor>();
try {
for (Object target : targets ) {
Class iface= target.getClass().getInterfaces()[0];
String ifaceName =iface.getName();
String serviceName = ifaceName.substring(0, ifaceName.lastIndexOf(IFACE_NAME));
Class processorClazz = Class.forName(serviceName.concat(PROCESS_NAME));
Object processorObj = processorClazz.getConstructor(iface).newInstance(iface.cast(target));
if (processorObj instanceof TProcessor) {
TProcessor processor = (TProcessor) processorObj;
processors.put(serviceName, processor);
}
}
} catch (Exception e) {
e.printStackTrace();
}
initMultiplexedProcessor();
}
/**
* 初始化多服务调用过程 TMultiplexedProcessor
* 并且注册服务
*/
private void initMultiplexedProcessor(){
if (processors.isEmpty()) {
return ;
}
multiplexedProcessor = new TMultiplexedProcessor();
Set<String> serviceNames = processors.keySet();
for (String serviceName : serviceNames) {
if (!processors.containsKey(serviceName)) {
continue;
}
multiplexedProcessor.registerProcessor(serviceName, processors.get(serviceName));
}
}
}
AppThriftServer.java 重点,服务启动
public class AppThriftServer implements ApplicationContextAware {
/**线程池**/
private static ExecutorService executorService;
// ApplicationContextAware 可以调用spring 生命周期获取上下文
private static ApplicationContext context;
public AppThriftServer() {
super();
// TODO Auto-generated constructor stub
executorService = Executors.newSingleThreadExecutor();
}
public void initThriftServer(){
executorService.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(" ThriftServer start ing ....");
TNonblockingServerSocket transport = null;
try {
//非阻塞 ServerSocket
transport =new TNonblockingServerSocket(new InetSocketAddress(29999));
// 获取 TProcessor
ThriftProcessorFactory thriftProcessorFactory=context.getBean(ThriftProcessorFactory.class);
TProcessor processor =thriftProcessorFactory.getProcessor();
// nio selectorThreads处理io, workerThreads 处理服务调用过程
TThreadedSelectorServer.Args args = new TThreadedSelectorServer.Args(transport);
args.processor(processor);
// customer也要TFramedTransport对应 否则报错
args.transportFactory(new TFramedTransport.Factory());
//二进制协议
args.protocolFactory(new TBinaryProtocol.Factory());
TThreadedSelectorServer server =new TThreadedSelectorServer(args);
server.serve();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (transport != null) {
transport.close();
}
}
}
});
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
context=applicationContext;
}
}
接着启动项目,服务端便开始监听;
接着是 customer 客户端
调用主体
public class App
{
private static ApplicationContext applicationContext;
public static void main( String[] args )
{
System.out.println( "Hello World!" );
init();
final TestService testService=applicationContext.getBean(TestService.class);
for (int i=0 ;i<10 ;i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
testService.doThriftTest();
}
}).start();
}
}
public static void init(){
applicationContext = new FileSystemXmlApplicationContext("/resources/applicationContext.xml");
}
}
TestService.java 中的 doThriftTest() 方法
ThriftServiceProxy 类的静态方法 getThriftClient() 获取接口类实例,在 doThriftTest()方法中是透明化的直接调用
public void doThriftTest(){
//运用动态代理 使thrift 接口透明化调用
IThriftInfoTestService.Iface client =ThriftServiceProxy.getThriftClient(IThriftInfoTestService.Iface.class);
Map<String, String> map =new HashMap<String, String>();
map.put("name", "庄杰森");
map.put("IThriftInfoTestService", "client");
map.put("content", "thrift 的 rpc 调用");
String name = "zhuangjiesen ...IThriftInfoTestService doing...";
try {
client.showInfoData(name, true, map);
} catch (TException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ThriftServiceProxy.java
可以链接 jdk动态代理
public class ThriftServiceProxy {
//client缓存
private static ConcurrentHashMap<String,Object> thriftClientCache;
public static <T> T getThriftClient(Class<T> clazz){
if (!clazz.isInterface()) {
throw new RuntimeException("类型错误");
}
if (thriftClientCache == null) {
thriftClientCache = new ConcurrentHashMap<String,Object>();
}
T client =null;
String cacheKey = clazz.getName();
if (thriftClientCache.containsKey(cacheKey)) {
client=(T)thriftClientCache.get(cacheKey);
} else {
//运用jdk代理方式实现接口类的方法,并且调用 同时 transport 资源通过代理进行close与open 简化代码-->类比事务实现
ThriftServiceProxyInvocation proxyInvocation =new ThriftServiceProxyInvocation();
proxyInvocation.setIfaceClazz(clazz);
client = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{ clazz }, proxyInvocation);
if (client != null) {
thriftClientCache.put(cacheKey, client);
}
}
return client;
}
}
ThriftServiceProxyInvocation.java 重点类
初学的因为每次调用方法时都要对transport (io资源) 进行开启关闭,所以就想设计将io资源代理起来可以直接透明调用;此处还用了反射方法
之后研究连接池时,也需要用到动态代理;
public class ThriftServiceProxyInvocation implements InvocationHandler {
private final static String IFACE_NAME="$Iface";
private final static String CLIENT_NAME="$Client";
private Class ifaceClazz;
public Class getIfaceClazz() {
return ifaceClazz;
}
public void setIfaceClazz(Class ifaceClazz) {
this.ifaceClazz = ifaceClazz;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println(" ThriftServiceProxyInvocation invoke doing before ....");
if (ifaceClazz == null) {
return null;
}
TTransport transport = null;
Object result = null;
try {
// 设置调用的服务地址为本地,端口
transport = new TSocket("127.0.0.1", 29999);
TFramedTransport framedTransport =new TFramedTransport(transport);
TBinaryProtocol binaryProtocol =new TBinaryProtocol(framedTransport);
TMultiplexedProtocol multiplexedProtocol =new TMultiplexedProtocol(binaryProtocol, IThriftInfoTestService.class.getName());
transport.open();
String ifaceName =ifaceClazz.getName();
String className = ifaceName.substring(0, ifaceName.lastIndexOf(IFACE_NAME));
String clientName = className.concat(CLIENT_NAME);
Class clientClazz = Class.forName(clientName);
//构造方法实例化 对应 Hello.Client client = new Hello.Client(protocol);
Object clientInstance= clientClazz.getConstructor(TProtocol.class).newInstance(multiplexedProtocol);
result=method.invoke(clientInstance, args);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
if (transport != null) {
transport.close();
}
}
System.out.println(" ThriftServiceProxyInvocation invoke doing after ....");
return result;
}
}