Dubbo系列(0)-RPC简介及简单实现

361 阅读3分钟

这是一个系列文章,将会从一个简单的rpc开始,介绍Dubbo的使用和基本原理。

IPC与RPC

RPC全称是远端过程调用,与之相对应的是本地过程调用,即进程间通信。在Linux环境下,进程间通讯可以通过管道,共享内存,信号量,Socket套接字,消息队列或信号量实现。RPC的一般流程是通过组件序列化请求,走网络到服务端,执行真正的服务代码,然后将结果返回给客户端,反序列化数据给调用方法。由于通讯细节被动态代理隐藏,因此整个调用过程就像是在本地调用一样。

通用RPC框架

  1. Proxy:封装服务端API,代理Client的请求,远程请求真正的方法并返回给Client。从Client的角度看,与调用本地方法没有任何区别。
  2. processor:通过反射机制定位具体的对象和方法。
  3. protocol:RPC协议,包括编解码,字节流解析和序列化、反序列化的工作。
  4. Remote:网络通讯相关功能,可以使用TCP,UDP,HTTP等实现。

简单RPC实现

Client Remote

使用socket进行网络通讯

import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;
public class ClientRemoter {
    public static final ClientRemoter client = new ClientRemoter();
    public byte[] getDataRemote(byte[] requestData)throws Exception{
        try (Socket socket = new Socket()){
            socket.connect(new InetSocketAddress("127.0.0.1",9999));
            socket.getOutputStream().write(requestData);
            socket.getOutputStream().flush();

            byte[] data = new byte[1024];
            int len = socket.getInputStream().read(data);
            return Arrays.copyOfRange(data,0,len);
        }
    }
}

Server Remote

监听外部请求,接收响应数据

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.*;

public class ServerRemoter {
    public static BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(3);
    private static final ThreadPoolExecutor threadPoolExecutor =
            new ThreadPoolExecutor(2
                    , 4
                    , 60
                    , TimeUnit.SECONDS
                    , blockingQueue
            );

    public void startServer(int port) throws IOException {
        final ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress(port));
        try {
            while (true) {
                Socket socket = serverSocket.accept();
                threadPoolExecutor.execute(new MyRunable(socket));
            }
        } finally {
            serverSocket.close();
        }
    }

    private static class MyRunable implements Runnable {
        private Socket socket;

        public MyRunable(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try (InputStream is = socket.getInputStream(); OutputStream out = socket.getOutputStream()) {
                byte[] data = new byte[1024];
                int len = is.read(data);
                ServiceProtocol.ProtocolModel model = (ServiceProtocol.ProtocolModel)ServiceProtocol.protocol.decode(Arrays.copyOfRange(data, 0, 1024)
                        , ServiceProtocol.ProtocolModel.class);
                Object object = ServiceProcessor.processor.process(model);
            } catch (Exception e) {

            }
        }
    }

}

Protocol

使用Hessian2进行序列化和反序列化


import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import lombok.Data;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

@Data
public class ServiceProtocol {
    public static final ServiceProtocol protocol = new ServiceProtocol();
    private Hessian2Output hessian2Output;
    private Hessian2Input hessian2Input;

    public byte[] encode(Object o) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        hessian2Output = new Hessian2Output(baos);
        hessian2Output.writeObject(o);
        hessian2Output.close();
        return baos.toByteArray();
    }

    public Object decode(byte[] data, Class clazz) throws Exception {
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        hessian2Input = new Hessian2Input(bais);
        Object o = hessian2Input.readObject(clazz);
        hessian2Input.close();
        return o;
    }

    @Data
    public static class ProtocolModel {
        private String clazz;
        private String method;
        private String[] argTypes;
        private Object[] args;
    }
}

Proxy

代理服务, 将请求的类名和方法名打包

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Proxy {
    public static<T> T getInstance(Class<T> clazz){
         return (T) Proxy.newProxyInstance(clazz.getClassLoader()
         ,new Class[]{clazz},new ServiceProxy(clazz));
    }

    public static class ServiceProxy implements InvocationHandler{
        private Class clazz;
        public ServiceProxy(Class clazz) {
            this.clazz = clazz;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            ServiceProtocol.ProtocolModel model= new ServiceProtocol.ProtocolModel();
            model.setClazz(clazz.getName());
            model.setMethod(method.getName());
            model.setArgs(args);
            String[] argType = new String[method.getParameterTypes().length];
            for (int i = 0; i < argType.length; i++) {
                argType[i] = method.getParameterTypes()[i].getName();
            }
            model.setArgTypes(argType);
             byte[] req = ServiceProtocol.protocol.encode(model);
             byte[] rsp = ClientRemoter.client.getDataRemote(req);
             return ServiceProtocol.protocol.decode(rsp,method.getReturnType());
        }
    }


}

Processor

通过反射执行对应的方法

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class ServiceProcessor {
    public static final ServiceProcessor processor = new ServiceProcessor();
    private static final ConcurrentMap<String, Object> PROCESSOR_INSTANCE_MAP = new ConcurrentHashMap<String, Object>();
    public boolean publish(Class clazz, Object obj) {
        return PROCESSOR_INSTANCE_MAP.putIfAbsent(clazz.getName(), obj) != null;
    }
    public Object process(ServiceProtocol.ProtocolModel model) throws Exception {
        try {
            Class clazz = Class.forName(model.getClazz());
            Class[] types = new Class[model.getArgTypes().length];
            for(int i = 0;i < types.length;i++){
                types[i] = Class.forName(model.getArgTypes()[i]);
            }
            Method method = clazz.getMethod(model.getMethod(),types);

            Object obj = PROCESSOR_INSTANCE_MAP.get(model.getClazz());
            return method.invoke(obj,model.getArgs());
        }catch (Exception e){
            return null;
        }
    }
}

Client

客户端

public class Client {

    public static void main(String[] args) {
        RpcService rpcService = ServiceProxyClient.getInstance(RpcService.class);
        rpcService.sayHello("content");
    }
}

Server

服务端

public interface RpcService {
    String sayHi(String name);
}
public class RpcServiceImpl implements RpcService {
    public String sayHi(String name) {
        return "Hello," + name;
    }
}

测试

/**
 * 服务端测试main执行代码
 */
public class ServerDemo {

    public static void main(String[] args) throws Exception {

        // 发布接口
        ServiceProcessor.processor.publish(RpcService.class,new RpcServiceImpl());

        // 启动server
        ServerRemoter remoter = new ServerRemoter();
        remoter.startServer(9999);

    }
}