RPC。远端过程调用。就是调用远端机器上的方法。
原理事实上非常easy。就是client上执行的程序在调用对象方法时,底层将针对该方法的调用转换为TCP/HTTP请求,发送到远端server,远端server监听固定port,收到这个TCP/HTTP请求后会解析出相关信息,包含client想要调用哪个类的哪个方法,參数是什么等,然后进行相应的调用,将调用结果再通过数据包发回就可以。
RPC中通常会有一些“契约”的概念。即client和服务端两方约定好的接口,表明服务端实现了哪些接口,client能够使用这些接口。以下以一个我实现的简单的RPC框架为例说明。
一、client
client通常会创建一个服务訪问代理,事实上就是这个契约接口类型的对象,以下是一个创建服务代理的样例:
//创建代理,调用服务
IHelloService proxy= (IHelloService)RpcProxyFactory.createProxy(IHelloService.class,"HelloService", 3000);
System.out.println("服务调用结果:"+proxy.sayHello("季义钦"));
当中createProxy接口的实现例如以下:
/**
* 创建远程调用代理
* @paramobjClass 接口类对象
* @paramserviceName 服务名称
* @paramURL 服务地址
* @paramtimeout 连接超时时限
* @return
* @throws Exception
*/
publicstatic Object createProxy(Class<?> objClass, String serviceName, StringURL, int timeout) throws Exception
{
//解析调用地址
String[]urls = URL.split(":");
StringipAddress = urls[1];
intport =Integer.parseInt(urls[2]);
//创建InvocationHandler
CBIPInvocationHandlerhandler = new CBIPInvocationHandler(ipAddress, port, timeout);
handler.setServiceName(serviceName);
//返回代理
returnProxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{objClass}, handler);
}
当中CBIPInvocationHandler是client代码的核心。是实现了InvocationHandler接口的Java动态代理,其invoke方法实现例如以下:
/**
* 全部方法调用都通过invoke来运行
*/
publicObject invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Objectresult = null;
try
{
//获取调用相关信息
StringbeanName = this.serviceName; //this.targrtObject.getClass().getSimpleName();
StringmethodName = method.getName();
String[]argTypes = createParamSignature(method.getParameterTypes());
//发起远程方法同步调用,传递调用信息
result = invokeSync(beanName,methodName, argTypes, args);
}
catch(Exceptionee)
{
ee.printStackTrace();
returnnull;
}
returnresult;
}
二、服务端
通过Mina框架实现的服务端程序获取来自client的方法调用的请求数据包后。解析出调用相关信息。
/**
* 收到来自client的消息
*/
@Override
public void messageReceived(IoSessionsession, Object message) throws Exception {
if(message instanceofCbipTcpRequest)
{
CbipTcpRequestrequest = (CbipTcpRequest)message;
try
{
//读取spring配置文件依据服务名称获取服务全限定名,然后反射出目标实例
ApplicationContextctx = new ClassPathXmlApplicationContext("dsf_config.xml");
ServiceConfigservice = (ServiceConfig)ctx.getBean(request.getBeanName());
Class<?>objClass = Class.forName(service.getServiceName());
Objectobj = objClass.newInstance();
//调用指定的方法
CBIPSkeletonskeleton = new CBIPSkeleton(obj, obj.getClass());
Objectresult = skeleton.invoke(request.getMethodName(), request.getArgs());
//回复
CbipTcpResponse response= new CbipTcpResponse();
response.setRequestID(request.getId()); // 请求ID
response.setBeanName(request.getBeanName());
response.setMethodName(request.getMethodName());
response.setResult(result);
session.write(response); //相似套接字
}catch(Exceptionee)
{
ee.printStackTrace();
}
}
}
(1)通过收到的client请求知道调用哪个类,从配置文件里读取该类的全限定名载入到JVM。反射出该类实例;
(2)通过反射出来的实例进行方法调用;
(3)通过Mina框架返回调用结果;
原文:http://www.cnblogs.com/wgwyanfs/p/6814784.html