手写简易版RPC框架基于Socket
什么是RPC框架?
RPC就是远程调用过程,实现各个服务间的通信,像调用本地服务一样。
RPC有什么优点?
- 提高服务的拓展性,解耦。
- 开发人员可以针对模块开发,互不影响。
- 提升系统的可维护性及高可用等。
基于socket思考:
- 怎么建立网络通信?
- 服务端怎么暴露服务并处理客户端请求?
- 客户端怎么去拿到服务并调用?
基于socket的通信的展示图: 流程 1---->2---->3---->4

上面的图形根据自己的理解画的--有些不足,但理解就行。
创建父工程order-server,子order-api,子order-producer,user-consumer的maven工程(也可以自己创建成独立的工程)。
创建过程省略....
项目工程图如下:

order-api工程:
- OrderApi类
package com.sqp.example.rpc; /** * @author sqp * @date 2020/7/17 17:38 */ public interface OrderApi { String getOrderName(String name); }
- RpcRequest类
package com.sqp.example.rpc; import java.io.Serializable; import lombok.Getter; import lombok.Setter; /** * @author sqp * @date 2020/7/17 17:57 */ @Setter @Getter public class RpcRequest implements Serializable { /** * 方法名 */ private String methodName; /** * 方法的入参参数 */ private Object[] args; /** * 方法的路径 */ private String className; /** * 参数类型 */ private Class[] types;
order-producer工程:
- OrderController类
package com.sqp.example.rpc; /** * @author sqp * @date 2020/7/17 17:39 */ public class OrderController implements OrderApi { @Override public String getOrderName(String name) { return "商品名称【"+name+"】"; } }
- ProxySocketServer类
package com.sqp.example.rpc; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 客户端监听 * @author sqp * @date 2020/7/17 17:41 */ public class ProxySocketServer { private final ExecutorService executorService = Executors.newCachedThreadPool(); public void publisher(Object service, int port){ ServerSocket serverSocket = null; try { // 创建一个serverSocket实例 serverSocket = new ServerSocket(port); // 一直监听客户端的请求 while(true){ // socket是一个阻塞IO还有连接阻塞 Socket socket =serverSocket.accept(); // 使用线程处理阻塞IO,这样接收消息这边就不需要阻塞 ,但受限于线程 executorService.submit(new ProcessorHandler(socket,service)); } } catch (IOException e) { e.printStackTrace(); }finally{ if(serverSocket != null){ try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
- ProcessorHandler类
package com.sqp.example.rpc; 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; /** * 线程处理类 * @author sqp * @date 2020/7/17 17:46 */ public class ProcessorHandler implements Runnable { /** * 监听返回的socket连接 */ private Socket socket; /** * 发布的服务 */ private Object service; /** * 构造方法 * @param socket * @param service */ public ProcessorHandler(Socket socket, Object service) { this.socket =socket; this.service=service; } @Override public void run() { ObjectInputStream inputStream = null; ObjectOutputStream outputStream = null; try{ // 获取接收的数据 inputStream = new ObjectInputStream(socket.getInputStream()); // 反序列化 RpcRequest rpcRequest = (RpcRequest) inputStream.readObject(); // 反射调用 Object res = invoke(rpcRequest); outputStream = new ObjectOutputStream(socket.getOutputStream()); outputStream.writeObject(res); outputStream.flush(); }catch(Exception e){ e.printStackTrace(); }finally { if(outputStream!= null){ try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(inputStream != null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 通过反射进行服务的调用 * @param rpcRequest * @return*/ private Object invoke(RpcRequest rpcRequest) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { // 获取class Class clazz = Class.forName(rpcRequest.getClassName()); // 找到目标的方法, 通过传入方法名称和参数类型 Method method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getTypes()); // 传入服务和参数 return method.invoke(service, rpcRequest.getArgs()); } }
- App类
package com.sqp.example.rpc; public class App { public static void main( String[] args ) { // new一个实例 OrderApi orderApi = new OrderController(); ProxySocketServer proxySocketServer = new ProxySocketServer(); // 发布服务 proxySocketServer.publisher(orderApi, 8080); } }
user-consumer工程:
- ProxySocketClient类
package com.sqp.example.rpc; import java.lang.reflect.Proxy; /** * @author sqp * @date 2020/7/17 18:22 */ public class ProxySocketClient { // 动态代理 public <T> T proxyClient(final Class<T> clazz, String host, int port){ return (T)Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] {clazz}, new RemInvocationHandler(host, port)); } }
- RemInvocationHandler类
package com.sqp.example.rpc; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author sqp * @date 2020/7/17 18:33 */ public class RemInvocationHandler implements InvocationHandler { private String host; private int port; public RemInvocationHandler(String host, int port) { this.host = host; this.port = port; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { RpcNetTransport rpcNetTransport = new RpcNetTransport(host, port); // 封装请求的参数,方法,类型,类名 RpcRequest rpcRequest = new RpcRequest(); rpcRequest.setMethodName(method.getName()); rpcRequest.setClassName(method.getDeclaringClass().getName()); rpcRequest.setArgs(args); rpcRequest.setTypes(method.getParameterTypes()); return rpcNetTransport.send(rpcRequest); } }
- RpcNetTransport类
package com.sqp.example.rpc; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; /** * @author sqp * @date 2020/7/17 18:41 */ public class RpcNetTransport { private String host; private int port; public RpcNetTransport(String host, int port) { this.host = host; this.port = port; } public Socket newSocket() throws IOException { return new Socket(host, port); } public Object send(RpcRequest rpcRequest) { ObjectInputStream inputStream = null; ObjectOutputStream outputStream = null; try { // 建立连接 Socket socket = newSocket(); outputStream = new ObjectOutputStream(socket.getOutputStream()); outputStream.writeObject(rpcRequest); outputStream.flush(); inputStream = new ObjectInputStream(socket.getInputStream()); return inputStream.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }finally { if (inputStream != null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(outputStream != null){ try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } }
- App类
package com.sqp.example.rpc; public class App { public static void main( String[] args ) { ProxySocketClient proxySocketClient = new ProxySocketClient(); OrderApi orderApi = proxySocketClient.proxyClient(OrderApi.class, "localhost", 8080); System.out.println(orderApi.getOrderName("文具盒")); } }
测试结果:

总结:
- 客户端建立通信,实现动态代理去获取代理类,将请求的消息内容组装发送到网络通信中,因为只有通过远程通信才能进行服务的调用。
- 服务端接收客户端请求连接是在serverSocket.accept(),然后对请求的数据进行处理,反序列化,通过拿到的内容进行反射调用。
虽然这个简易版的RPC有很多局限性,大家不必过多纠结,但是符合我们RPC的通信原理。
针对上面的可以改造成用spring的注解方式。下期我再修改,这里我感谢下我的MIC老师。
写的不好大家别喷,大家多包涵,不过有错误希望大家指出来,一起学习,一起快乐。多手写代码记忆更深刻!

浙公网安备 33010602011771号