推荐阅读:
看完点个赞呗,啊呜~
Rpc框架是个啥?
“老王,Rpc是个啥,俺怎么没听说过?” 小王一脸疑惑的问向老王。
“Rpc你都不知道?亏你还是我带出来的。” 老王一脸鄙视的望向小王。
“有那个时间我早去跟学妹深入交流了。” 小王小声嘀咕道。
“好吧,好吧,今天我就跟你讲讲Rpc是个啥,你可得给我好好听。”
“Rpc(Remote Procedure Call)是远程过程调用的意思。举个栗子,部署在两台服务器的服务A1,A2。此时A1想调用A2的服务,采用传统的调用方式是无法调用的。然而Rpc框架解决了这个问题,它可以在不同的系统之间进行通讯。”
“原来如此,老王,那Rpc是咋调用的?” 小王再次问向老王。
“你急个啥,让我慢慢给你道来。”
“Rpc框架实现服务的提供方和消费方。服务的提供方把服务提供出去,让消费方去消费。这里还涉及到服务的发现与注册,这以后再谈”
“至于调用吗,听的再多不如教你写一次”
“老王威武,童颜巨......” 小王对老王夸赞道。 “那是,隔壁老王的称号可不是白叫的”。老王自豪的抬起头,摸了摸头上仅剩的几根头发。
手写基本Rpc
先写暴露服务的方法
暴露服务的方法是将该服务暴露出去,已便于调用
1.1 创建一个暴露服务的方法,这里需要接受两个参数,一个是服务对象,一个是端口号
<code>public
static
void
exportService
(
final
Object service,int
port) 复制代码/<code>
1.2 判断参数是否合法
<code>if
(service==null
){throw
new
IllegalArgumentException("service is null"
); }if
(port<=0
|| port>65535
){throw
new
IllegalArgumentException("Invalid Error, port is not access "
); } 复制代码/<code>
1.3 创建Socket对象
<code>ServerSocket serverSocket =new
ServerSocket(port); System.out
.println("服务已经启动----"
); 复制代码/<code>
1.4 获取socket,采用线程,创建I/O流
<code>final
Socket socket = serverSocket.accept();new
Thread(new
Runnable() { ObjectInputStream objectInputStream =null
; ObjectOutputStream objectOutputStream =null
;public
void
run
()
{ } } }).start(); 复制代码/<code>
1.5 将对象存入到I/O流中
<code>try
{ objectInputStream =new
ObjectInputStream(socket.getInputStream());String
methodName = objectInputStream.readUTF(); Class>[] paramTypes = (Class>[])objectInputStream.readObject();Object
[]arguments
= (Object
[])objectInputStream.readObject(); Method method = service.getClass().getMethod(methodName, paramTypes);Object
result = method.invoke(service,arguments
); objectOutputStream =new
ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeObject(result); }catch
(Exception e) { e.printStackTrace(); }finally
{try
{ objectOutputStream.close(); objectInputStream.close(); socket.close(); }catch
(Exception e) { e.printStackTrace(); } } 复制代码/<code>
“老王,为什么这里是while(true)?这不是死循环了吗?” 小王问老王。 “这你就不懂了吧,这里并不是死循环,而是代表暴露服务的方法一直运行着,每当一次调用请求进来的时候才会执行。” “这里我们可以用一个requestNum来记录调用的情况”
完整的暴露服务代码
<code>public
static
void
exportServer
(
final
Object service,int
port)throws
Exception {if
(service==null
){throw
new
IllegalArgumentException("service is null"
); }if
(port<=0
|| port>65535
){throw
new
IllegalArgumentException("Invalid Error, port is not access "
); } ServerSocket serverSocket =new
ServerSocket(port); System.out.println("服务已经启动----"
);while
(true
){final
Socket socket = serverSocket.accept();new
Thread(new
Runnable() { ObjectInputStream objectInputStream =null
; ObjectOutputStream objectOutputStream =null
;public
void
run
()
{try
{ requestNum++; System.out.println("端口:"
+port+"接收请求"
+requestNum+"次"
); objectInputStream =new
ObjectInputStream(socket.getInputStream()); String methodName = objectInputStream.readUTF(); Class>[] paramTypes = (Class>[])objectInputStream.readObject(); Object[] arguments = (Object[])objectInputStream.readObject(); Method method = service.getClass().getMethod(methodName, paramTypes); Object result = method.invoke(service, arguments); objectOutputStream =new
ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeObject(result); }catch
(Exception e) { e.printStackTrace(); }finally
{try
{ objectOutputStream.close(); objectInputStream.close(); socket.close(); }catch
(Exception e) { e.printStackTrace(); } } } }).start(); } } 复制代码/<code>
调用服务的方法
该方法主要用来调用对应的服务
2.1 创建一个调用服务方法,这里需要接受三个参数,接口类型,ip地址,端口号
<code>public
static
T
referServer
(
final
Class interfaceClass,final
String host,final
int
port) 复制代码/<code>
2.2 判断参数合法性
<code>if
(interfaceClass ==null
){throw
new
IllegalArgumentException("interfaceClass is null"
); }if
(host ==null
){throw
new
IllegalArgumentException("host is null"
); }if
(port<=0
|| port>65535
){throw
new
IllegalArgumentException("Invalid port :"
+ port); }if
(!interfaceClass.isInterface()){throw
new
IllegalArgumentException("interfaceClass is not interface class "
); } 复制代码/<code>
2.3 采用jdk的动态代理返回服务对象
<code>return
(T)Proxy.newProxyInstance(interfaceClass.getClassLoader(),new
Class>[]{interfaceClass},new
InvocationHandler() {public
Object
invoke(Object
proxy, Method method,Object
[] args) throws Throwable { Socket socket =new
Socket(host,port); System.out.println("主机ip地址:"
+host+",端口号:"
+port); ObjectOutputStream objectOutputStream =null
; ObjectInputStream objectInputStream =null
;try
{ objectOutputStream =new
ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeUTF(method.getName()); objectOutputStream.writeObject(method.getParameterTypes()); objectOutputStream.writeObject(args); objectInputStream =new
ObjectInputStream(socket.getInputStream());Object
result = objectInputStream.readObject();if
(resultinstanceof
Throwable) {throw
(Throwable)result; }return
result; }catch
(Exception e){ e.printStackTrace(); }finally
{ objectInputStream.close(); objectOutputStream.close(); socket.close(); }return
null
; } }); 复制代码/<code>
完整的调用服务代码
<code>public
static
T
referServer
(
final
Class interfaceClass,final
String host,final
int
port)throws
Exception{if
(interfaceClass ==null
){throw
new
IllegalArgumentException("interfaceClass is null"
); }if
(host ==null
){throw
new
IllegalArgumentException("host is null"
); }if
(port<=0
|| port>65535
){throw
new
IllegalArgumentException("Invalid port :"
+ port); }if
(!interfaceClass.isInterface()){throw
new
IllegalArgumentException("interfaceClass is not interface class "
); }return
(T)Proxy.newProxyInstance(interfaceClass.getClassLoader(),new
Class>[]{interfaceClass},new
InvocationHandler() {public
Objectinvoke
(Object proxy, Method method, Object[] args)
throws
Throwable { Socket socket =new
Socket(host,port); System.out.println("主机ip地址:"
+host+",端口号:"
+port); ObjectOutputStream objectOutputStream =null
; ObjectInputStream objectInputStream =null
;try
{ objectOutputStream =new
ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeUTF(method.getName()); objectOutputStream.writeObject(method.getParameterTypes()); objectOutputStream.writeObject(args); objectInputStream =new
ObjectInputStream(socket.getInputStream()); Object result = objectInputStream.readObject();if
(resultinstanceof
Throwable) {throw
(Throwable)result; }return
result; }catch
(Exception e){ e.printStackTrace(); }finally
{ objectInputStream.close(); objectOutputStream.close(); socket.close(); }return
null
; } }); } 复制代码/<code>
测试手写的Rpc框架
“小王啊,我们来测试一下吧”
创建服务接口以及实现类
<code>public
interface
MyInterface
{String
hello
()
; }public
class
MyInterfaceImpl
implements
MyInterface
{public
Stringhello
()
{return
"HELLO WORLD"
; } } 复制代码/<code>
启动两个main方法进行测试
<code>public
class
MyTest
{public
static
void
main
(String[] args)
throws Exception { MyInterfaceImpl server =new
MyInterfaceImpl(); MyRpcFramework.export
(server,6000
); } }public
class
MyTest2
{public
static
void
main
(String[] args)
throws Exception { MyInterface server = MyRpcFramework.refer(MyInterface.class,"127.0.0.1"
,6000
);for
(int
i =0
;i<10
;i++){ System.out.println(server.hello()+"--"
+i); Thread.sleep(1000
); } } } 复制代码/<code>
测试结果
总结
以上便是手写基本Rpc框架的全部内容,作者希望采用小王和老王的对话来更加生动的描写出技术原理以及实现,感谢大家的阅读。天高地远,我们江湖再见!
作者:武当王也
链接:https://juejin.im/post/5e96e572518825739d4086c0
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。