初识RPC框架+JAVA实现

RPC是什么?

RPC是远程过程调用(Remote Procedure Call)的缩写形式。
当我们需要在客户机本地调用远程服务器的方法时,RPC的作用就体现出来。

RPC的处理过程是怎样的?

假设有一台客户机C(Client),想要调用远程服务器S(Server)的天气服务(Weather).
如果这个服务是在C本地已经存在的话,我们可以直接使用Weather wt = new Weather();
wt.getService();方式来获取服务,但是此时这个天气服务的对象并不存在于本地,即客户机本地不能直接使用该服务。这时,我们就需要使用到一个代理对象A(Agent),来获取远程服务器的Weather服务。
因此,在这种情况下,我们的RPC过程如下:

  1. C使用A向服务器调用远程服务
  2. A将该请求通过网络传输到B(请求某个服务,并传递服务需要的参数)
  3. B在本地调用后将结果通过网络传输给A,同时C也完成了服务

关于远程的服务,客户端要和服务器达成“共识”,即需要一个约定的接口来提供服务。服务器设置接口,告诉客户端,客户端在得到接口后与服务器达成“共识”。这样客户端就知道如何使用这个服务。

实现举例

1.创建客户机RPCClient项目,在包com.rpcClient下创建了两个java文件:Agent.java(处理对象),Client.java(客户机)

package com.rpcClient;

import com.interfaceServer.Function;

public class Client {
	 
		public static void main(String[] args) { 
			
			Function  q=(Function)Agent.getRemote(Function.class);
			String s=q.getUser(1000);
			System.out.println("服务器端返回结果是 "+s);
		}
}

我们知道客户机与服务器在服务上达成了“共识”,即服务器把自己能够提供的服务和使用的方式以接口形式告诉了客户机(import com.interfaceServer)。当客户机想使用这项服务时,使用代理对象来获取服务类对象,这里是q,q可以提供的服务是getUser()。但实际上客户机本地并没有这项服务,通过远程调用,让我们感觉好像在客户机里写了Function类一样(这种感觉由Agent代理来实现)。

2.客户机发出请求之后,Agent怎么传递给服务器呢?
我们已经提到“共识”:在服务器项目中,我们创建了两个包。

文件
com.interfaceServerFunction.java,MethodPara.java
com.ServerImpFunction.java,Serverrpc.java

com.interfaceServer包就是需要的“共识”。

package com.interfaceServer;
//服务器提供的功能接口
public interface Function {
	public String getUser(int id);
}

package com.interfaceServer;
//来用在网络间收发远程调用的方法的相关参数
//类的对象,要通过网络发送,所以要实现一个标记接口
public class MethodPara implements java.io.Serializable {
	public String interfaceName;//对应接口的名字
	public String methodName;//方法的名字
	public Class[] paraType;//方法的参数类型
	public Object[] args;//方法的参数对象 
}

MethodPara告诉了Agent,你如果想调用我的服务的话,你得先告诉我你想用哪个服务,你提供给我参数,我把服务的结果告诉你。
服务器把这个包导出成jar文件给客户机使用。(达成共识)在这里插入图片描述

package com.rpcClient;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;

import com.interfaceServer.MethodPara;

//用来取得远端对象的"代理"
//客户端,和服务器端,只共享了一个接口
public class Agent {
	//取得远程对象  clazz 哪个接口的对象
		public static Object getRemote(Class  clazz){
			String iNameString=clazz.getName();
			//方法调用处理器:
			InvokeAgent  iaAgent=new InvokeAgent(iNameString);
			//取得了代理对象
			return	java.lang.reflect.Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{ clazz},iaAgent);
		 	} 
}
class InvokeAgent implements  java.lang.reflect.InvocationHandler{
	private String interfaceName;
	
	public InvokeAgent(String interfaceName){
		this.interfaceName=interfaceName;
	}
	

	//当客户端调用方法时,执行的代码:
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		String methodNameString=method.getName();
		Class[] methodType=method.getParameterTypes(); 
		//然后,把这些,方法相关的参数,发送给服务器
		MethodPara mp=new MethodPara();
		mp.methodName=methodNameString;
		mp.interfaceName=this.interfaceName;
	    mp.paraType=methodType;
	    mp.args=args;
	    //建立网络连结
	    java.net.Socket socket=new java.net.Socket("127.0.0.1",9999);
	    //通过对象流来读写 发送方法对象
	    java.io.ObjectOutputStream ous=new ObjectOutputStream(socket.getOutputStream());
	    ous.writeObject(mp);
		System.out.println("客户机己经把方法的相关参数发送给服务器");

	    //同步,读取服务器执行方法后,返回的结果
	    java.io.ObjectInputStream oins=new ObjectInputStream(socket.getInputStream());
		Object result=oins.readObject(); 
		System.out.println("客户机收到服务器反回的一个结果"); 
 		return result;
	}
}

3.Agent将服务需要的参数通过网络传输过去后,由getRemote得到远程对象,服务器根据方法名和参数找到对应需要的服务,将结果返回。
在服务器端的com.Server包中,具有两个java文件:ImpFunction.java,Serverrpc.java
ImpFunction是具体实现Function服务的类,Serverrpc是服务器。

package com.Server;

import com.interfaceServer.Function;

public class ImpFunction implements Function{

	public String getUser(int id) {
		String s="serverTime:"+(id/10)+"--"+System.currentTimeMillis();
		return s;
	}

}

package com.Server;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;

import com.interfaceServer.MethodPara;

public class Serverrpc {
	public static void main(String[] args)throws Exception {
		//收到一个接口名,和方法的相关参数,去调用对应的实现了接口的类中的方法,返回结果
	   java.net.ServerSocket ss=new java.net.ServerSocket(9999);
	   System.out.println("服务器己启动在端口9999");
	   while(true){
		     Socket socket=ss.accept();
		     System.out.println("有客户机进入/");
		     //读取各户端发来的参数
		     java.io.ObjectInputStream oins=new ObjectInputStream(socket.getInputStream());
		    MethodPara para=(MethodPara)oins.readObject();
		    System.out.println("客户机发来的服务名字(接口名字是:"+para.interfaceName);
		    if(para.interfaceName.equals("com.interfaceServer.Function")){ 
//		    	 com.serverImp.ImpQuery query=new com.serverImp.ImpQuery();
		    	 //动态装载,在服务器端实现了接口的类
		    	 Class  c=Class.forName("com.Server.ImpFunction"); 
		    	 Object o=c.newInstance();//利用类的无参构造器,创建对象
	 	    	 //反射得到要调用的方法对象
		    	 Method m=c.getMethod(para.methodName, para.paraType);
		    	 //在对象上调用方法:
		    	Object  result=m.invoke(o, para.args);
		    	//把这个调用结果,发送给客户机:
		    	 java.io.ObjectOutputStream ous=new ObjectOutputStream(socket.getOutputStream());
		 	    ous.writeObject(result);
		     } 
		     //调用 
		   }
		}
}

结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
另一篇深层次的解读RPC博客

心得

RPC是一种用于本地远程调用存储于其他机器上服务的框架,就好比是图书馆的书籍分类目录(共识–接口–服务列表)一样,图书馆(服务器)把这个目录给你,你想找什么样的书(服务需求)就看一下目录,按照目录的提示(使用接口)去图书馆里找正确的书籍,不过是你委托一个人(Agent)来帮你而已,找到了他再告诉你。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值