java 远程调用 RPC
本文内容纲要:
-1.概念
-1.1框架
-1.1.1RMI
-1.1.2THrift
-1.1.3Dubbo(Dubbox)
-1.1.4gRPC
-2.RPC的实现
-2.1实现技术方案
-2.2RPC框架架构
-2.3Demo
-2.3.1服务提供者接口定义
-2.3.2服务提供者接口实现
-2.3.3RPC框架服务中心
-2.3.4服务提供者
-2.3.5服务消费者
-运行结果
1.概念
RPC,全称为RemoteProcedureCall,即远程过程调用,它是一个计算机通信协议。它允许像调用本地服务一样调用远程服务。它可以有不同的实现方式。如RMI(远程方法调用)、Hessian、Httpinvoker等。RPC是与语言无关的。直观说法就是A通过网络调用B的过程方法。也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。
1、首先要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,B服务器的IP,以及应用绑定的端口,还有方法的名称,这样才能完成调用
2、方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式
3、在B服务器上完成寻址后,需要对参数进行反序列化,恢复为内存中的表达方式,然后找到对应的方法进行本地调用,然后得到返回值,
4、返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给应用
1.1框架
1.1.1RMI
java自带远程调用框架
1.1.2THrift
thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在C++,Java,Go,Python,PHP,Ruby,Erlang,Perl,Haskell,C#,Cocoa,JavaScript,Node.js,Smalltalk,andOCaml这些编程语言间无缝结合的、高效的服务。
1.1.3Dubbo(Dubbox)
服务治理,也可以做微服务
1.1.4gRPC
gRPC是一个高性能、开源和通用的RPC框架,面向移动和HTTP/2设计。目前提供C、Java和Go语言版本,分别是:grpc,grpc-java,grpc-go.其中C版本支持C,C++,Node.js,Python,Ruby,Objective-C,PHP和C#支持.
开源中国组织翻译的《gRPC官方文档中文版》:http://doc.oschina.net/grpc
gRPC基于HTTP/2标准设计,带来诸如双向流、流控、头部压缩、单TCP连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
2.RPC的实现
RPC能够让本地应用简单、高效地调用服务器中的过程(服务)。它主要应用在分布式系统。如Hadoop中的IPC组件。但怎样实现一个RPC框架呢?
从下面几个方面思考,仅供参考:
1.通信模型:假设通信的为A机器与B机器,A与B之间有通信模型,在Java中一般基于BIO或NIO;。
2.过程(服务)定位:使用给定的通信方式,与确定IP与端口及方法名称确定具体的过程或方法;
3.远程代理对象:本地调用的方法(服务)其实是远程方法的本地代理,因此可能需要一个远程代理对象,对于Java而言,远程代理对象可以使用Java的动态对象实现,封装了调用远程方法调用;
4.序列化,将对象名称、方法名称、参数等对象信息进行网络传输需要转换成二进制传输,这里可能需要不同的序列化技术方案。如:protobuf,Arvo等。
2.1实现技术方案
下面使用比较原始的方案实现RPC框架,采用Socket通信、动态代理与反射与Java原生的序列化。
2.2RPC框架架构
RPC架构分为三部分:
1)服务提供者,运行在服务器端,提供服务接口定义与服务实现类。
2)服务中心,运行在服务器端,负责将本地服务发布成远程服务,管理远程服务,提供给服务消费者使用。
3)服务消费者,运行在客户端,通过远程代理对象调用远程服务。
2.3Demo
2.3.1服务提供者接口定义
HelloService.java
1packagecom.loveincode.rpc;
2
3publicinterfaceHelloService{
4
5Stringhello(Stringname);
6
7}
2.3.2服务提供者接口实现
HelloServiceImpl.java
1packagecom.loveincode.rpc;
2
3//HelloServices接口实现类:
4publicclassHelloServiceImplimplementsHelloService{
5
6publicStringhello(Stringname){
7return"hello,"+name;
8}
9
10}
2.3.3RPC框架服务中心
RpcFramework.java
1packagecom.loveincode.rpc;
2
3importjava.io.ObjectInputStream;
4importjava.io.ObjectOutputStream;
5importjava.lang.reflect.InvocationHandler;
6importjava.lang.reflect.Method;
7importjava.lang.reflect.Proxy;
8importjava.net.ServerSocket;
9importjava.net.Socket;
10
11publicclassRpcFramework{
12/**
13*暴露服务
14*
15*@paramservice
16*服务实现
17*@paramport
18*服务端口
19*@throwsException
20*/
21publicstaticvoidexport(finalObjectservice,intport)throwsException{
22if(service==null)
23thrownewIllegalArgumentException("serviceinstance==null");
24if(port<=0||port>65535)
25thrownewIllegalArgumentException("Invalidport"+port);
26System.out.println("Exportservice"+service.getClass().getName()+"onport"+port);
27ServerSocketserver=newServerSocket(port);//前面都是验证调用是否符合规则,这里在被调用端开一个服务。下面就是死循环运行。
28for(;;){
29try{
30finalSocketsocket=server.accept();
31newThread(newRunnable(){//对每一个请求new一个线程,匿名类
32@Override
33publicvoidrun(){
34try{
35try{
36ObjectInputStreaminput=newObjectInputStream(socket.getInputStream());
37try{
38StringmethodName=input.readUTF();
39Class<?>[]parameterTypes=(Class<?>[])input.readObject();
40Object[]arguments=(Object[])input.readObject();
41ObjectOutputStreamoutput=newObjectOutputStream(socket.getOutputStream());//接收客户端传来的方法名、参数类型、参数
42try{
43Methodmethod=service.getClass().getMethod(methodName,parameterTypes);//在本地生成对应的方法,
44Objectresult=method.invoke(service,arguments);//调用
45output.writeObject(result);//返回结果
46}catch(Throwablet){
47output.writeObject(t);
48}finally{
49output.close();
50}
51}finally{
52input.close();
53}
54}finally{
55socket.close();
56}
57}catch(Exceptione){
58e.printStackTrace();
59}
60}
61}).start();
62}catch(Exceptione){
63e.printStackTrace();
64}
65}
66}
67
68/**
69*引用服务
70*
71*@param<T>
72*接口泛型
73*@paraminterfaceClass
74*接口类型
75*@paramhost
76*服务器主机名
77*@paramport
78*服务器端口
79*@return远程服务
80*@throwsException
81*/
82@SuppressWarnings("unchecked")
83publicstatic<T>Trefer(finalClass<T>interfaceClass,finalStringhost,finalintport)throwsException{
84if(interfaceClass==null)
85thrownewIllegalArgumentException("Interfaceclass==null");
86if(!interfaceClass.isInterface())
87thrownewIllegalArgumentException("The"+interfaceClass.getName()+"mustbeinterfaceclass!");
88if(host==null||host.length()==0)
89thrownewIllegalArgumentException("Host==null!");
90if(port<=0||port>65535)
91thrownewIllegalArgumentException("Invalidport"+port);
92System.out.println("Getremoteservice"+interfaceClass.getName()+"fromserver"+host+":"+port);
93return(T)Proxy.newProxyInstance(interfaceClass.getClassLoader(),newClass<?>[]{interfaceClass},
94newInvocationHandler(){//用动态代理的方法进行包装,看起来是在调用一个方法,其实在内部通过socket通信传到服务器,并接收运行结果
95publicObjectinvoke(Objectproxy,Methodmethod,Object[]arguments)throwsThrowable{
96Socketsocket=newSocket(host,port);
97try{
98ObjectOutputStreamoutput=newObjectOutputStream(socket.getOutputStream());
99try{
100output.writeUTF(method.getName());
101output.writeObject(method.getParameterTypes());
102output.writeObject(arguments);
103ObjectInputStreaminput=newObjectInputStream(socket.getInputStream());
104try{
105Objectresult=input.readObject();
106if(resultinstanceofThrowable){
107throw(Throwable)result;
108}
109returnresult;//返回结果
110}finally{
111input.close();
112}
113}finally{
114output.close();
115}
116}finally{
117socket.close();
118}
119}
120});
121}
122}
2.3.4服务提供者
RpcProvider.java
1packagecom.loveincode.rpc;
2
3publicclassRpcProvider{
4publicstaticvoidmain(String[]args)throwsException{
5HelloServiceservice=newHelloServiceImpl();
6RpcFramework.export(service,1234);
7}
8}
2.3.5服务消费者
RpcConsumer.java
packagecom.loveincode.rpc;
publicclassRpcConsumer{
publicstaticvoidmain(String[]args)throwsException{
HelloServiceservice=RpcFramework.refer(HelloService.class,"127.0.0.1",1234);
for(inti=0;i<Integer.MAX_VALUE;i++){
Stringhello=service.hello("World"+i);
System.out.println(hello);
Thread.sleep(1000);
}
}
}
运行结果
执行RpcProvider结果:
Exportservicecom.loveincode.rpc.HelloServiceImplonport1234
执行RpcConsumer结果:
Getremoteservicecom.loveincode.rpc.HelloServicefromserver127.0.0.1:1234
hello,World0
hello,World1
hello,World2
hello,World3
hello,World4
hello,World5
hello,World6
hello,World7
hello,World8
hello,World9
...
本文内容总结:1.概念,1.1框架,1.1.1RMI,1.1.2THrift,1.1.3Dubbo(Dubbox),1.1.4gRPC,2.RPC的实现,2.1实现技术方案,2.2RPC框架架构,2.3Demo,2.3.1服务提供者接口定义,2.3.2服务提供者接口实现,2.3.3RPC框架服务中心,2.3.4服务提供者,2.3.5服务消费者,运行结果,
原文链接:https://www.cnblogs.com/loveincode/p/7348177.html