当前位置: 首页 > news >正文

手写一个简单的RPC框架

学习RPC框架,由繁化简,了解其本质原理

文章目录

  • 项目简介
    • 什么是RPC?
    • 项目模块
  • 项目代码
    • common模块
    • client模块
    • server模块
    • framework模块
    • 测试

项目简介

什么是RPC?

RPC(Remote Procedure Call)即远程过程调用,不同于本地调用,RPC是指调用远端机器的函数或方法,且不需要关心底层的调用细节,如网络协议和传输协议等,对于调用者来说,和调用本地方法没有什么区别。

项目模块

  1. common模块:定义了用户接口和实体类User
  2. client模块:调用RPC框架的代理类,获取结果
  3. server模块:
  • 实现common的接口,把实现类注册到注册中心中
  • 调用RpcServer开启socket
  • 根据RpcRequest类的信息,获取到注册中心的实现类
  • 执行方法,返回结果,通过socket返回
  1. Rpc framework
  • 注册中心
  • RpcRequest,装载类的信息
  • RpcServer:创建socket,接受客户端的请求

在这里插入图片描述

项目代码

common模块

实体类和定义的接口

package com.rpc.common;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** @Author: Yangmiao* @Date: 2023/2/8 10:37* @Desc: 网络中传输的信息*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User implements Serializable {private Integer id;private String name;private Integer age;private int sex;
}
package com.rpc.common;/*** @Author: Yangmiao* @Date: 2023/2/8 10:38* @Desc:*/
public interface IUserService {User getById(Integer id);User getUsername(String userName);
}

client模块

package com.rpc.client;import com.rpc.common.IUserService;
import com.rpc.framework.proxy.RpcProxy;/*** @Author: Yangmiao* @Date: 2023/2/8 11:39* @Desc:*/
public class Client {public static void main(String[] args) {RpcProxy rpcProxy = new RpcProxy();IUserService productService = (IUserService) rpcProxy.remoteCall("localhost", 10000, IUserService.class);System.out.println("productService = " + productService.getById(10));}
}

server模块

package com.rpc.server;import com.rpc.common.IUserService;
import com.rpc.framework.Registry;
import com.rpc.framework.RpcServer;/*** @Author: Yangmiao* @Date: 2023/2/8 11:37* @Desc:* https://www.cnblogs.com/fantongxue/p/16004920.html*/
public class Server {/*** 把接口和实现类注册到RPC的注册中心,然后通过RPC的RPCServer开启一个serversocket,监听某一个端口。* @param args*/public static void main(String[] args) {Registry.put(IUserService.class.getName(), UserServiceImpl.class);new RpcServer().provide(10000);}
}
package com.rpc.server;import com.rpc.common.User;
import com.rpc.common.IUserService;/*** @Author: Yangmiao* @Date: 2023/2/8 11:35* @Desc:*/
public class UserServiceImpl implements IUserService {@Overridepublic User getById(Integer id) {return User.builder().id(id).name("yangmiao").age(100).sex(1).build();}@Overridepublic User getUsername(String userName) {return User.builder().name(userName).build();}
}

framework模块

package com.rpc.framework;import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;/*** @Author: Yangmiao* @Date: 2023/2/8 10:39* @Desc: 注册中心*/
public class Registry {private final static HashMap<String, Class> map = new HashMap<>();private final static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();/*** 读缓存* @param key* @return*/public static Class get(String key){// 读锁Lock writeLock = readWriteLock.writeLock();// 写锁Lock readLock = readWriteLock.readLock();Class v = null;readLock.lock();try {v = map.get(key);}finally {readLock.unlock();}if (v != null){return v;}// 缓存中不存在writeLock.lock();try {v = map.get(key);if (v==null){// 1.查询数据库// 2.写入缓存map.put(key,v);}}finally {writeLock.unlock();}return v;}/*** 写缓存* @param key* @param value* @return*/public static Class put(String key, Class value){Lock writeLock = readWriteLock.writeLock();writeLock.lock();try {return map.put(key,value);}finally {writeLock.unlock();}}public static boolean containsKey(String key){return map.containsKey(key);}}
package com.rpc.framework;import lombok.Data;import java.io.Serializable;/*** @Author: Yangmiao* @Date: 2023/2/8 10:41* @Desc:*/
@Data
public class RpcRequest implements Serializable {private String className;private String methodName;private Class[] types;private Object[] params;}
package com.rpc.framework;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @Author: Yangmiao* @Date: 2023/2/8 10:42* @Desc:*/
public class RpcServer {/*** 创建线程池*/private ExecutorService executors = Executors.newFixedThreadPool(5);public void provide(int port){try {ServerSocket serverSocket = new ServerSocket(port);while (true){Socket socket = serverSocket.accept();executors.execute(new ProcessHandler(socket));}} catch (IOException e) {e.printStackTrace();}}
}
package com.rpc.framework;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: Yangmiao* @Date: 2023/2/8 10:50* @Desc: 处理服务端逻辑*/
public class ProcessHandler implements Runnable {private Socket socket;public ProcessHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {ObjectInputStream objectInputStream = null;ObjectOutputStream objectOutputStream = null;try {objectInputStream = new ObjectInputStream(socket.getInputStream());RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();Class clazz = null;// 判断是否存在于注册中心中if (Registry.containsKey(rpcRequest.getClassName())){clazz = Registry.get(rpcRequest.getClassName());}Method method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getTypes());Object result = method.invoke(clazz.newInstance(), rpcRequest.getParams());// 返回结果objectOutputStream = new ObjectOutputStream(socket.getOutputStream());objectOutputStream.writeObject(result);objectOutputStream.flush();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}finally {try {if (objectInputStream !=null){objectInputStream.close();}if (objectOutputStream !=null){objectOutputStream.close();}}catch (IOException e){e.printStackTrace();}}}
}

代理

package com.rpc.framework.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;/*** @Author: Yangmiao* @Date: 2023/2/8 11:18* @Desc: 创建动态代理*/
public class RpcProxy<T> {public T remoteCall(String host,int port,Class clazz){return (T) Proxy.newProxyInstance(clazz.getClassLoader(),(Class<?>[]) new Class[]{clazz},new RemoteInvocationHandler(host,port,clazz));}
}
package com.rpc.framework.proxy;import com.rpc.framework.RpcRequest;import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;/*** @Author: Yangmiao* @Date: 2023/2/8 11:22* @Desc: 代理类执行的逻辑*/
public class RemoteInvocationHandler implements InvocationHandler {private String host;private int port;private Class clazz;public RemoteInvocationHandler(String host,int port,Class clazz){this.host = host;this.port = port;this.clazz = clazz;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {RpcRequest rpcRequest = new RpcRequest();rpcRequest.setClassName(clazz.getName());rpcRequest.setMethodName(method.getName());rpcRequest.setTypes(method.getParameterTypes());rpcRequest.setParams(args);ObjectOutputStream objectOutputStream = null;ObjectInputStream objectInputStream = null;try {Socket socket = new Socket(host,port);// 发送消息objectOutputStream = new ObjectOutputStream(socket.getOutputStream());objectOutputStream.writeObject(rpcRequest);objectOutputStream.flush();// 接受结果objectInputStream = new ObjectInputStream(socket.getInputStream());Object readObject = objectInputStream.readObject();return readObject;}catch (Exception e){e.printStackTrace();}finally {try {if (objectInputStream !=null){objectInputStream.close();}if (objectOutputStream!=null){objectOutputStream.close();}}catch (IOException e){e.printStackTrace();}}return null;}
}

测试

在这里插入图片描述
在这里插入图片描述

相关文章:

手写一个简单的RPC框架

学习RPC框架&#xff0c;由繁化简&#xff0c;了解其本质原理 文章目录项目简介什么是RPC&#xff1f;项目模块项目代码common模块client模块server模块framework模块测试项目简介 什么是RPC&#xff1f; RPC&#xff08;Remote Procedure Call&#xff09;即远程过程调用&am…...

【剑指offer】旋转数组的最小数字

&#x1f451;专栏内容&#xff1a;剑指offer⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录一、题目描述1、题目2、示例示例1示例2二、题目分析1、暴力法2、二分法三、代码汇总1、暴力法2、二分法一、题目描述 1、题…...

【Dorker】Portainer轻量级可视化工具

文章目录Portainer简介登录Portainer第一次登录需创建admin&#xff0c;访问地址&#xff1a;xxx.xxx.xxx.xxx:9000选择local选项卡后本地docker详细信息展示安装nginx私有镜像仓库管理Portainer简介 Portainer是Docker的图形化管理工具&#xff0c;提供状态显示面板、应用模板…...

基于 vue.js 进行组件封装的方案

摘要&#xff1a;本文将介绍如何基于 vue.js 进行组件封装的方案。我们将从分析组件封装的优势开始&#xff0c;然后依次介绍 vue.js 的基本概念&#xff0c;以及如何创建、封装和使用自定义组件。最后&#xff0c;我们将通过一个实际的示例&#xff0c;演示如何实现一个基于 v…...

【Unityc#专题篇】之c#基础篇

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…...

Python(白银时代)——模块、包、异常

异常 概念 程序运行时&#xff0c;如果Python 解释器遇到了错误&#xff0c;会停止程序运行&#xff0c;并且提示错误信息&#xff0c;这就是异常 程序停止执行并提示错误信息的动作&#xff0c;称为 抛出异常 异常捕获 try: 里面的代码&#xff0c;不确定是否能够正常执行. …...

小程序和Vue写法的区别

小程序和Vue写法的区别主要有以下几点&#xff1a; 语法不同&#xff1a;小程序使用的是WXML、WXSS和JS&#xff0c;而Vue使用的是HTML、CSS和JSX。 数据绑定方式不同&#xff1a;小程序使用的是双向数据绑定&#xff0c;而Vue使用的是单向数据流。 1&#xff09;在小程序中需…...

如何实现分布式锁

一、锁的作用 锁是为了解决多线程情况下&#xff0c;对于共享资源的访问安全问题。 但是当系统是分布式的时候&#xff0c;本地锁已经没法锁住所需要的资源&#xff0c;因为本地获取了锁&#xff0c;其他系统无法得知本地锁的情况。 分布式锁&#xff0c;是独立于系统的第一方…...

使用VS2019连接Microsoft SQL Server Compact 4.0数据库

简介 SQL Server Compact Edition是微软推出的一个适用于嵌入到移动应用的精简数据库产品&#xff0c;Windows Mobile开发人员能够使用SQL Server CE开发出将数据管理能力延展到Window Mobile移动设备上的应用程序。虽然SQL Server CE占用的磁盘空间只有3到5兆左右&#xff0c…...

Vue2 和 Vue3 的对比

Vue2 vs Vue3 Vue 是一款流行的 JavaScript 框架&#xff0c;用于构建交互式 Web 界面。Vue2 和 Vue3 是 Vue.js 的两个版本。Vue3 是 Vue.js 的最新版本&#xff0c;于 2020 年 9 月正式发布。Vue3 有许多改进和新功能&#xff0c;下面我们将对 Vue2 和 Vue3 进行比较。 性能…...

[数据结构]二叉树的链式存储结构

目录 二叉树的链式存储结构&#xff1a;&#xff1a; 1.创建一颗二叉树 2.二叉搜索树简介 3.前序、中序以及后序遍历 4.层序遍历 5.求一棵树的节点个数代码实现 6.求一棵树的高度代码实现 7.求叶子节点个数代码实现 8.求第K层节点个数代码实现 9.二叉树查找值为x的节点 二叉树…...

黑马程序员 Redis 踩坑及解决

文章目录实战篇p30 短信登录-隐藏用户敏感信息p50 优惠券秒杀-添加优惠券p69 秒杀优化-异步秒杀思路p81 达人探店-点赞排行榜p87 好友关注-实现滚动分页查询问题 1问题 2p90 附近商铺-实现附近商户功能实战篇 p30 短信登录-隐藏用户敏感信息 问题描述&#xff1a;登录后会跳转…...

Matlab实现粒子群算法

粒子群算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;是一种群体智能算法&#xff0c;通过模拟自然界中鸟群、鱼群等生物群体的行为&#xff0c;来解决优化问题。 在PSO算法中&#xff0c;每个个体被称为粒子&#xff0c;每个粒子的位置表示解空间中…...

tailwindcss 写原生html

需要注意&#xff1a;html文件中引入的是output.css input.css写那三行预留的就可以了打包的时候只要打包html output.css img文件夹句ok&#xff0c;其他都不用原理是运行时生产output.css文件&#xff0c;直接【注意&#xff01;注意&#xff01;注意&#xff01;class"…...

Java开发一年不到,来面试居然敢开口要20K,面完连8K都不想给~

前言 我的好朋友兼大学同学老伍家庭经济情况不错&#xff0c;毕业之后没两年自己存了点钱加上家里的支持&#xff0c;自己在杭州开了一家网络公司。由于公司不是很大所以公司大部分的开发人员都是自己面试的&#xff0c;近期公司发展的不错&#xff0c;打算扩招也面试了不少人…...

LeetCode题解 20(17,79) 电话号码的字母组合,单词搜索<回溯>

文章目录电话号码的字母组合(17)代码解答单词搜索(79)代码解答电话号码的字母组合(17) 思路: 根据题意我们必须根据数字获取对应的字符数组&#xff0c;因此我们先定义1个字符数组表示这个电话表 private String[] letters {"","","abc","…...

路径之谜 蓝桥杯 89

题目描述小明冒充 X 星球的骑士&#xff0c;进入了一个奇怪的城堡。城堡里边什么都没有&#xff0c;只有方形石头铺成的地面。假设城堡地面是 nn 个方格。如下图所示。按习俗&#xff0c;骑士要从西北角走到东南角。可以横向或纵向移动&#xff0c;但不能斜着走&#xff0c;也不…...

Mysql数据库如何调优

MYSQL数据库调优 索引 1、对于常用的查询字段加索引&#xff0c;但如果常用字段只有几个常量值就不需要加索引&#xff0c;或者使用索引会失效的情况&#xff1b; 2、索引失效的情况&#xff1a; ​ 1、索引列使用函数&#xff0c;计算&#xff08;加减乘除等&#xff09; …...

CAN(FD)记录仪在新能源汽车整车控制器(VCU)、电池管理系统(BMS)、电机控制器(MCU)、发动机ECU中的应用,免去出差烦恼

今天介绍CAN(FD)记录仪在新能源汽车整车控制器&#xff08;VCU&#xff09;、电池管理系统&#xff08;BMS&#xff09;、电机控制器&#xff08;MCU&#xff09;、发动机ECU中的应用 第一步&#xff1a;新能源汽车整车控制器&#xff08;VCU&#xff09;先供上电&#xff0c…...

【设计模式】23种设计模式之七大原则

【设计模式】23种设计模式之七大原则什么是设计模式的原则1、单一职责原则基本介绍案例分析注意事项2、接口隔离原则基本介绍案例分析代码实现3、依赖倒转原则基本介绍案例分析依赖传递的三种方式注意事项4、里氏替换原则关于继承性的思考和说明基本介绍案例分析5、开闭原则ocp…...

python - 文件操作

1. 概念 计算机内存通常分为两种类型&#xff1a;主存储器和辅助存储器。 主存储器是计算机中最重要的存储器类型之一。它是计算机中用于存储正在运行的程序和数据的存储器。主存储器通常是易失性的&#xff0c;这意味着当计算机关闭时&#xff0c;其中存储的数据将被删除。主存…...

docker打包golang应用

一、错误的打包方式在本地环境编译&#xff0c;然后将可执行程序放入 alpine(docker.io/alpine:latest)准备web程序package mainimport ("fmt""net/http" )func main() {server : &http.Server{Addr: ":8888",}http.HandleFunc("/"…...

redis 内容总结

目录redis 内容列举Redis和Memcached比较Redis简介1、Redis 数据结构2、Redis的持久化机制3、Redis 内容管理&#xff08;淘汰策略/删除策略&#xff09;4、Redis 事务5、Redis 缓存三大问题6、Redis 集群7、Redis 应用redis 内容列举 官网&#xff1a;https://redis.io/ 中文…...

贪心算法(一)

一、概念 贪心算法的核心思想是&#xff0c;在处理一个大问题时&#xff0c;划分为多个局部并在每个局部选择最优解&#xff0c;并且认为在每个局部选择最优解&#xff0c;那么最后全局的问题得到的就是最优解。 贪心算法可以解决一些问题&#xff0c;但是不适用于所有问题&a…...

【栈和队列OJ题】有效的括号用队列实现栈用栈实现队列设计循环队列

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录OJ题1.有效的括号1.1…...

kuernetes 资源对象分析报错

文章目录1. pod 状态1.1 容器启动错误类型1.2 ImagePullBackOff 错误1.3 CrashLoopBackOff1.4 Pending2. Service 连接状态3. Ingress 连接状态1. pod 状态 创建一个 pod-status.yaml apiVersion: v1 kind: Pod metadata:name: runninglabels:app: nginx spec:containers:- na…...

动态内存的开辟

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C &#x1f525;座右铭&#xff1a;“不要等到什么都没有了&#xff0c;才下…...

【蓝桥杯-筑基篇】搜索

&#x1f353;系列专栏:蓝桥杯 &#x1f349;个人主页:个人主页 目录 递归树 1.递归构建二进制串 2.全排列的 DFS 解法 3.全排列的 BFS 解法 4.数的划分法 5.图书推荐 递归树 递归树是一种用于分析递归算法时间复杂度的工具。它可以将递归算法的执行过程可视化&#xf…...

week5-质数-最大公约数-快速幂-组合计数-博弈论

蓝桥 等差数列——欧几里得算法质数质数的判定——试除法分解质因数——试除法筛质数——埃氏筛法筛质数——线性筛法质数问题质数距离约数试除法求约数约数个数约数之和最大公约数-欧几里得算法(辗转相除法)扩展欧几里得算法裴蜀定理应用——线性同余方程消灭老鼠Hankson的趣…...

CloudCompare 二次开发(6)——插件中拖拽添加Qt窗口(区域生长算法为例)

目录 一、概述二、插件制作三、Cmake编译四、插件代码五、结果展示一、概述 手动拖拽的方式搭建Qt对话框界面的制作流程,以PCL中的点云区域生长算法为例进行制作。 二、插件制作 1、将....\plugins\example路径下的ExamplePlugin复制一份并修改名字为CCPointCloudProcess。 …...