要想先理解远程调用,那么首先必不可少的就是理解本地调用
本地调用
我们当初的单体应用项目所有的请求就是本地调用。例如:将一个学生信息进行修改,首先前台http请求后端接口,调用当前项目所提供的功能规范进行传参,最后实现调用修改功能
远程调用
在上诉的过程中,本地http请求当前项目提高的学生修改功能,但是真正的更改功能服务在另一个项目中运行,也就是说你真实要访问的服务在另一个主机,你在当前请求的接口功能修改其实就是涉及了RPC的一次调用过程,先本地请求调用传参,然后由本地服务向另一个主机发送数据请求,接受server端的数据返回,当前的请求就相当于是Client端。
在微服务的设计中,一个服务A如果访问另一个Module下的服务B,可以采用HTTP REST传输数据,并在两个服务之间进行序列化和反序列化操作,服务B把执行结果返回过来。
为什么不直接进行Http
当大家看了上面的远程调用的过程会想,client端为什么不直接远程http请求服务端呢?主要两个原因
1.HTTP在应用层中完成,整个通信的代价较高,远程过程调用中直接基于TCP进行远程调用,数据传输在传输层TCP层完成,更适合对效率要求比较高的场景,RPC主要依赖于客户端和服务端之间建立Socket链接进行,底层实现比REST更复杂。
2.由于采用了RPC,各个厂商为适应不同的平台而遵循这个RPC规范,中间具体调用传输,采取什么序列化技术由他们自己选择,所有就有了很多RPC框架,如dubbo
下面会附送自定义RPC实现的过程源码,建议不懂的大家可以先了解下 Socket io 网络这些基本概念
Server端
业务逻辑代码
package com.demo.provider;
import rpcservice.RpcRequest;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
public class ProcessorHandler implements Runnable{
private Socket socket;
private Object service;
public ProcessorHandler(Socket socket, Object service) {
this.socket = socket;
this.service = service;
}
@Override
public void run() {
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
try {
//获取client 请求的输入流,获取相关参数信息
objectInputStream = new ObjectInputStream(socket.getInputStream());
//将流信息转换对象
RpcRequest request = (RpcRequest)objectInputStream.readObject();
//执行业务逻辑
Object result =invoke(request);
//将result返回结果 返回client
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
} catch (IOException | ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}finally {
if(objectInputStream!=null){
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(objectOutputStream!=null){
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private Object invoke(RpcRequest request) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//通过反射 执行方法
String className = request.getClassName();
Object[] parameters = request.getParameters();
Class[] types = new Class[parameters.length];
for (int i = 0; i < parameters.length; i++) {
types[i]=parameters[i].getClass();
}
Class<?> aClass = Class.forName(className);
Method method = aClass.getMethod(request.getMethodName(),types);
Object result = method.invoke(service, parameters);
return result;
}
}
Client端
jdk动态代理
Client业务逻辑执行
package com.rpc.client;
import rpcservice.RpcRequest;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class RpcNetTransport {
private String host;
private int port;
public RpcNetTransport(String host, int port) {
this.host = host;
this.port = port;
}
public Object send(RpcRequest request){
Object result = null;
ObjectInputStream objectInputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
//client请求远程服务器
Socket socket = new Socket(host, port);
//传输数据
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(request);
objectOutputStream.flush();
//接收Server端返回的参数
objectInputStream = new ObjectInputStream(socket.getInputStream());
result = objectInputStream.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
if(objectInputStream!=null){
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(objectOutputStream!=null){
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}