RPC 的全称是 Remote Procedure Call 是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即无论是调用本地接口/服务的还是远程的接口/服务,本质上编写的调用代码基本相同。
1:服务提供者A向注册中心注册自身服务(接口及实现类作为参数)
2:服务提供者接口类作为参数,通过动态代理生成一个动态Proxy实现类对象P。
3:动态生成的类P主要功能:socket连接注册中心;向注册中心发送 接口类名称/方法/方法参数 等参数;
4:注册中心接收到客户端发来的 接口类/方法/参数 然后根据接口类名称从已经注册的服务中获取对应的服务;
5:通过反射获取服务的方法,调用方法;
6:返回结果
7:消费者获取结果;
1:dubbo
2:springcloud
package com.test.rpc;
import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class RpcNioTest {
private static Integer port =8888;
public static void main(String[] args) throws Exception {
RpcClientProxy clientProxy = new RpcClientProxy(MyService.class,port);
MyService myService = clientProxy.getObj();
System.out.println(myService.getVal("123456"));
}
}
//服务提供者
interface MyService{
public String getVal(String param);
}
class MyServiceImpl implements MyService{
@Override
public String getVal(String param) {
return "Rpc Test"+param;
}
}
//注册中心
class MyCenter{
private static Integer port =8888;
public static void main(String[] args) throws Exception {
start();//启动注册中心
}
private static Map services = new HashMap<>();//服务列表
//注册服务
public void register(Class service,Class impl){
services.put(service.getName(),impl);
}
//启动注册中心
public static void start() throws Exception {
NioTest nioTest = new NioTest();
nioTest.startSocket();
}
//socket服务
static class NioTest{
public void startSocket() throws Exception {
//声明一个selector
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);//非阻塞
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//注册到selector
while (true){
//阻塞消息
selector.select();
Set selectionKeySet = selector.selectedKeys();//获取所有消息
Iterator it = selectionKeySet.iterator();
while (it.hasNext()){//遍历所有消息
SelectionKey selectionKey = it.next();//拿到消息,删除Set中的信息
selectionKeySet.remove(selectionKey);
// selector.selectedKeys().remove(selectionKey);
//判断消息类型
if(selectionKey.isValid() && selectionKey.isAcceptable()){//连接信息
//生成一个通道
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector,SelectionKey.OP_READ);
}
if(selectionKey.isValid() && selectionKey.isReadable()){//读消息
SocketChannel channel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(2048);
channel.read(byteBuffer);
String msg = new String(byteBuffer.array()).trim();
System.out.println(channel.hashCode()+"客户端消息:"+msg);
JSONObject obj = JSONObject.parseObject(msg);
//消息类型
String msgType = obj.getString("msgType");
if("rpc".equals(msgType)){
String className = obj.getString("className");
String methodName = obj.getString("methodName");
Class>[] parameterTypes = getPTypes(obj);
Object[] arguments = obj.getString("arguments").split(",");//获取客户端发来的参数
//从注册中心中查找服务
Class service = services.get(className);
Method method = service.getMethod(methodName,parameterTypes);
Object res = method.invoke(service.newInstance(),arguments);
//返回客户端结果
channel.write(ByteBuffer.wrap(res.toString().getBytes(StandardCharsets.UTF_8)));
}
}
}
}
}
private Class>[] getPTypes(JSONObject obj) throws ClassNotFoundException {
String []types=obj.getString("types").split(",");
Class> []res = new Class[types.length];
for(int i=0;i {
private static Class service;
private static Integer port;
public RpcClientProxy(Class service,Integer port){
this.service=service;
this.port = port;
}
public T getObj(){
T obj = (T) Proxy.newProxyInstance(service.getClassLoader(),new Class[]{service},new RpcProxy());
return obj;
}
static class RpcProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectOutputStream output = null;
ObjectInputStream input = null;
/**
* 下面是动态生成的代理类做的动作
* 1:socket连接注册中心
* 2:向注册中心发送接口类,方法,参数等
* 3:注册中心收到上述信息,根据上述信息的接口类名称参数 获取注册到该注册中心的服务
* 4:通过反射获取服务的方法,调用
* 5:接收注册中心调用接口返回的结果
*/
try {
// 2.创建Socket客户端,根据指定地址连接远程服务提供者
socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1", port));
output = new ObjectOutputStream(socket.getOutputStream());
// 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
JSONObject param = new JSONObject();
param.put("msgType","rpc");
param.put("className",service.getName());
param.put("methodName",method.getName());
param.put("arguments",args);
param.put("types","java.lang.String");
/*output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(service.getName());//向注册中心发接口类
output.writeUTF(method.getName());//向注册中心发送方法名
output.writeObject(method.getParameterTypes());//向注册中心发送参数类型
output.writeObject(args);//向注册中心发送方法参数*/
output.write(param.toJSONString().getBytes());
// 4.同步阻塞等待服务器返回应答,获取应答后返回
input = new ObjectInputStream(socket.getInputStream());//等待注册中心返回结果
Object obj = input.readObject();
return obj;
} finally {
if (socket != null) socket.close();
if (output != null) output.close();
if (input != null) input.close();
}
}
}
}