手把手教你写一个基本的Rpc框架
看完点个赞呗,啊呜~

Rpc结构是个啥?
“老王,Rpc是个啥,俺怎么没听说过?” 小王一脸疑问的问向老王。
“Rpc你都不知道?亏你仍是我带出来的。” 老王一脸轻视的望向小王。
“有那个时间我早去跟学妹深入A t c U 6 C交流了。” 小王小声嘀咕道。
“好吧,好吧,今天我就跟H i 5 C y你讲讲7 _ i } f $ R CRpc是个啥,你可得给我好好听。”
“Rpc(Remote ProceH , i P B 0 3 Kdure Call)是远程过程调用的意思。举个栗子,8 ! f D A m j p部署在两台服务器的服务A1,A2。此时A1想调用A2的服o { ~务,选用传统的调用办法是无法调用的。但是Rpc结构处理了这个问题,它能够在不同的体系之间进行通讯。”
“原来如此,老王,那Rp] – ] w [ m I }c是咋调用的?” 小王再次问向老王。
“你急个啥,让我渐渐给你道来。”
“Rpc结构完成服务的供给方和消费方。服务的供给方把服务供给出去,让消费方去消费。这儿还涉及到服务的发现与注册,这今后再谈”
“至于调用吗,听的再多不如教你写一次”
“老王威武,童颜巨..2 i Z F J & @….” 小王对老王夸奖道。
“那是,隔壁老王的称号可不是白叫的”。老王骄傲的抬起头,摸了摸头上仅剩的几根头发。
手写基本Rpc
先@ B J S t j v写露出服务的办法
露出服务的办法是将该b o H服务露出出去,已便于调用
1.1 创立一个露出服q w h ^ 5 J务的办法,这儿需要承受两个参数,一个是服务目标,一个是端口号
public static void exportService(final Object service,int port)
1.2 判别参数是否合法
//判别服务是否为null
if (servic :e==null){
throw new IllegalArgumentException("service is nu% r n } 4ll");
}
//判别端口是否合法
if (port<=0 || port>65535){
throU B = g ! z g c Jw new IllegalArgumentExce/ L ! } V t % k rption("Invalid Error, port is not access ")) l D X q;
}
1.3 创立Socket目标
ServerD [ B : [ %Socket serverSocket = new ServerSocket(port);
//这儿要加一个输出,标志服务已经发动
System.out.println("服务已经发动----");
1.4 获取socket,选用线程,创立I/O流
//获取一个socket
final Socket socket = serf U 5 * 7 b J JverSocket.accept();
new Thread(new Runnable() {
//创立输入输出流
ObjectO i ( ( L * 2InpuH o m s G m 5 [tStream objectInputStream = null;
ObjectOutputStream objectOutputStream = null;
@Override
public void run() {
}
}
}).start();
1.5 将目标存入到I/O流中
try {
objectInputStreamt Y U p | ] u : = new ObjectInputStream(socket.getInputStream());
//获取办法名
String methodName = objectInputStream.readUTF();
//办法参数类型数组
Class<?>[] pa. 5 3 Y S f o , dramTy= v spes = (Class<?>[])objectInputStream.readObject();
//办法参数
Object[] argument) $ : Zs = (Object[])objectInputStrz I Team.readObject();
//反射
Method method = service& 1 - X.getClass().^ _ #getMethod(met% * b N ihodName, paramTypes);
Object result = method.invoke(service, arguments);
//将成果读到输出流中
objectOutputStream =I J i e * new ObjectOutpuT ^ StStream(sock. S 3 c | | pet.getW h z 4OutputStream())% D $;
objectOutputStream.writeObject(rel ^ [ f $ ,sult);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
//封闭资源,顺着开,倒着封闭
objectOutputStream.c! s - z tlose();
objectInputStream.close();
socket.close();
} catch (Excepti7 b ]on e) {
e.printStackTrace();
}
}
“老王,为什么这儿k 9 ( N P n N是while(true)?这不是死循环了吗?” 小王问老王。
“这你就不懂了吧,这儿并不7 b S =是死循环,而是代表露出服务的办法D = L M C一向运转着,每当4 H ] 2 _一次调用恳求进来的时候才会履行。”
“这儿咱们能够用一个requestNum来记录调用8 ^ Q k 4的状况”
完好的露出服务代码
/**
* 露出服务
* @param service 服务目标
* @param port 端口
* @throws Exception
*/
public static void exportServer(final Object service,int port) throws Exception {
//判别服务是否为null
if (service==null){
throw new IllegalArgumentException("service is null");
}
//判别端口是否合法
if (H V ) 3port<=0 || port>65535){
throw new IllegalArgumentExceptio5 H Kn("Invalid Error, port is not access ");
}
//运用Socket完成
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务已经发动----");
while (true){
//获取一个socket
final Socket+ % v A N B socket = serverSocket.accept(Z e [ T F);
new Thread(new Runnable() {
//创立输入输出流
ObjectInputStream objectInputStream = nu{ C : b c m Z U Xll;
ObjectOutputStream objectOutputStream = null;
@Override
public void run() {
try {
requestNuS K xm++;
System.out.println("端口:"+port+"接纳恳求"; 0 @ u = @+requestNum+"次");
objectInputStream = new ObjectInputStream(socket.getInputSU ` T h H b i Xtream());
//获取办法名
String methodName = objectInputStream.readUTF();
//办法参数类型数组
Class<?>[] p| $ UaramTypes = (Class<?>[])objectInputStream.readObject 0 t();
//办法参数
Object[] arguments = (ObjecK t Y a pt[])objecS % ] ltInputStream/ ^ H z x ? h P.readObject();
//反射
Method method = service.ge[ q P 2 _ H Q U ltClass()X * 6 i.getMethod(methodName, paramTypes);
Object result = methoK ( hd.invoke(service, ara X - C m J b S 9guments);
//将成果读到输出流S P m i 3 c ^ S中
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
} catch (Exception e) {
e.printStao l G g d : SckTrace();
}finally {
try {
/y s 7/封闭资源,顺着开,倒着2 R A B y封闭
objectOutputStream.close();
objectInputStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
}
调用服务的办法
该办法首要用来调用对应的服务
2.1 创立一个调用服务办法,这儿需要承受三个参数,接口D u # 5 ; – S r `类型,ip地址,端口号
public static <T> T referServer(final Class<T> interfaceClass,final String host,final int port)
2.2 判别参数合法性
if (interfaceClass ==null){
throw new Illegal+ i 1 O CArgumei C { C ! o ; D #ntException("interfaceClass is null");
}
if (host ==null){
throw new IllegalArgumentException("host is null");
}
if (port<=0 || port>65535){
throw new IllegaG % slArgumentException("Invalid port :" + port);
}
if (!interfaceClass.isInterface()){
throw new IllegalArgumentExceptio, 8 0 (n("interfaceC; r . 9 }lass is not interface class ");
}
2.3 选用jdk} _ A ] ! ; z c的动态代理返回服务目c N B J 9 H t x 标
return (T)Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, new InvocatK J = O iionHandler() {
@Override
public Object invT , Q @ ! 1 : 1oke(Object pi E $ D O V C troxy, Method method, Object[] args) throws Throwable {
//获取socket
Socket socket = new Socket(host,port);
System.out.println("主机ip地址:8 D - b w"+host+",端口号:"+port);
//创立输入输出流
ObjectOutputStk 8 j m 4ream objectOutputStream = null;
ObjectInputStream objectInputStrF f # .eam = null;
try {
//这儿选用装修器模式
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
//向流中写入办法名,参数类型,参数
objectOutputStream.writeUTF(methodw & } B b.getName());
objectOutputStream.writeObject(method.getPa4 D y ( s .rameterTypes());
objE 0 C n 8ectOutputStream.w 4 *writeObject(args);
objectInputSt+ R B ) 5 # 3ream = n D ` f t rew ObjectInputStream(socket.getInputStre& $ [ z } t U _am()I s w ^);
Object result = objectInp. J U R eutStream.readObjU 9 @ect();
//抛出反常
if (result instanceof Throwable) {
throw (Thro_ . e 5wable)result;
}
returK _ Nn result;
}catch (Exception e){
e.printStackTrace();
}finally {
objectInputStream.close();
objectOutputStream.close();
socket.close();
}
return null;
}
});
完v % t P b } p . v好的调用服务代码
/**
*
* @param interfaceClass 接口类型
* @parx | ? q w m k X `am host 主机ip
* @param porty L V J ! _ 5 端口号
* @param <T> 接口泛型
* @reh Z O 3turn4 N K W N H F 远程服务目标
* @throws Exception
*/
public static <T> T ref9 O 0erServer(final Class<T> interfaceClass,final StrP j r @ ^ ! j 8 Uing hoH } = L Cst,final int port)thr m f T v F 7ows Exception{
if (interfaceClass ==null){
throw new IllegalArgumentException("interfaceClass is null");
}
if (K e s T m ( rhost ==null){
th@ U %row new IllegalArgument: - y _ y BException("host is null");
}
if (port<=0 |! r : K I f * l| port>65535){
throw new IllegalArr 3 V N A [ xgumentExceptioG [ O V - B Z qnp u ? ] i D S z("InvaT 4 7 f }lid port :" + port);
}
if (!interfaceClass.isInterface()){
throw new IllegalArgumentException("interfaceClass is not interface class ");
}
returnt ? n O | K | (T)Proxy.newProxk z e OyInstancs U pe(4 + w ^ AinterfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, new InvocationH! # A O h W t 7 Sandler() {
@Override
public Object in= L ^ p W $ C ,voke(Object proJ { w +xy, Method method, Object[] args) throws Throwable {
//获取socket
Sockei P w gt socket = new Socket(host,port);
System.out.println("主Z / 2 P v F C n机ip地址:"+host+",端口号:"+port);
//创立输入输出流
ObjectOutputSo K m x : )tream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
try {
//这儿选用装修器模式
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
//向流中写入办法名,参数类型,参数
objectOutputStream.writeUTF(method.getName());C S 4 W ; 3 ( l :
objectOutputStream.writeObject(method.E e k b ) A FgetParameterTypes());
objectOutputStream.writeObject(ar/ S egs);
objectInputStream = new ObjectInputStream(socket.getInputStream());
ObD . h T c T rject result = objectInputStream.readObjeck ? / r h / h n dt();
//抛出反常
if (result instanceof Throwable) {
throw (ThrowableZ c })result;
}
return result;
}catch (Exception e){
e.printStackTraA L T k p l Ece();
}finally {
obj* a 5 t m k |ectInputStream.close();
objectOutput4 b = 9 @Stream.close();
socket.close();
}
return null;
}
});
}
测验手写的Rpc结构
“小王啊,咱们来测验一下吧”
创立服务接口以及完成类
pq ; : a 2 1ublic inth I Z F K I m v Kerface MyInterface {
String hello();
}
public class MyInterfaceImpl implements MyInt[ $ jeru q @ d m x 7face {
@Override
public String heu c :llo() {
return "HELLO WORLD";
}
}
发动两个main办法进行测验
public class MyTest {
public static void main(String[] argsr m v d ^ m 1 3) throws Exception {
//创立服务
MyInterfaceImpl server = new MyInterfaceImpl();
//露出服务
MyRpcFramework.export(server,6000);
}
}
public class MyTest2 {
public static void main(String[] args) throws Exception {
//调用; f r ) x w r 8服务
MyInterface server = MyRpcFramework.referE x :(MyInterface.class, "127.0.0.1", 6000);
for (int i = 0;i<10;i++){
SysteG & | ; Q Sm.out.println(servG 2 0 /er.hello()+"j i v--"+i);
Thread# - s + O 0 Q _ `.sleep(1000);
}
}
}
测验成果


总结
以上就是手写基本Rpc结构的全部内容,作者期望选用小王和老王的对话来更加生动的描写出技术原理^ h E v – 以及完成,感谢我们的阅览。天高地远,咱们江湖再会!