使用 Socket和动态代理以及反射 实现一个简易的 RPC 调用

使用 Socket、动态代理、反射 实现一个简易的 RPC 调用


我们前面有一篇 socket 的文章,再之前,还有一篇 java动态代理的文章,本文用到了那两篇文章中的知识点,需要的话可以回顾一下。


下面正文开始:

我们的背景是一个名为cuihua-snack(翠花小吃店)的客户端,要调用cuihua-core(翠花核心厨房)的服务端的接口,要求采用RPC的方式调用。
首先,我们创建两个项目cuihua-snack、cuihua-core
在这里插入图片描述

在这里插入图片描述
其中,cuihua-core 包含两个模块(关于 maven的模块化开发 可以再去了解一下),core-api中定义了客户端与服务端共同需要的接口和参数;core-service 则是服务端的主要逻辑。

我们有这样一张系统调用关系示意图。
在这里插入图片描述
① 服务端启动socket服务;
② 客户端开始调用,通过代理的方式调用;
③ 代理中包含 socket 客户端,与服务端建立连接后,将请求接口的对象信息封装后进行序列化。
④ 服务端接收到 socket 请求后,反序列化拿到请求的对象信息。
⑤ 通过反射,调用接口实现类的方法并返回结果。
⑥ 服务端对执行结果序列化并通过socket 返回给客户端。
⑦ 客户端对服务端返回的数据进行反序列化后,输出。
以上七个步骤,就是整个简易RPC的调用过程。


下面我们来看代码:
首先看 core-api 中的代码:
在这里插入图片描述

/*** 上菜服务*/
public interface DishService {String servePickedChineseCabbage(RequestDTO dto);
}
/*** 上菜requestDTO*/
@Data
public class RequestDTO implements Serializable {/*** 菜量*/private String quantityType;//big;medium;small;/*** 是否加辣*/private boolean spicy;/*** 冷热*/private String coldOrHot;//cold/hot
}
/*** RPC Request*/@Data
public class RpcRequest implements Serializable {private String className;private String methodName;private Object[] args;private Class[] types;}

再来看 core-service的代码:
在这里插入图片描述

public class DishServiceImpl implements DishService {public String servePickedChineseCabbage(RequestDTO dto) {System.out.println(dto);return "Please wait a moment! The dish you want will come soon!";}
}
public class RpcService {private DishService service;public RpcService(DishService service){this.service = service;}public void serverRun() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {ServerSocket serverSocket = new ServerSocket(8000);while(true) {Socket socket = serverSocket.accept();handler(socket);}}private void handler(Socket socket) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {//读取 socket 传输的数据ObjectInputStream objectinputstrem = new ObjectInputStream(socket.getInputStream());RpcRequest rpcRequest = (RpcRequest) objectinputstrem.readObject();String result = (String) this.invoke(rpcRequest);//将结果写回 socketObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());objectOutputStream.writeObject(result);objectOutputStream.flush();}private Object invoke(RpcRequest request) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {//通过反射进行服务的调用Class clazz=Class.forName(request.getClassName());//找到目标方法Method method=clazz.getMethod(request.getMethodName(),request.getTypes());return method.invoke(service,request.getArgs());}
}
public class App 
{public static void main( String[] args ) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {DishService dishService = new DishServiceImpl();RpcService rpcService = new RpcService(dishService);rpcService.serverRun();}
}

最后,我们来看 cuihua-snack的代码:
在这里插入图片描述

public class CuihuaInvocationHandler implements InvocationHandler {private String host;private int port;public CuihuaInvocationHandler(String host,int port){this.host = host;this.port = port;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//开启客户端SocketClient socketClient = new SocketClient(host,port);//请求参数RpcRequest rpcRequest = new RpcRequest();rpcRequest.setArgs(args);rpcRequest.setTypes(method.getParameterTypes());rpcRequest.setClassName(method.getDeclaringClass().getName());rpcRequest.setMethodName(method.getName());//发送Object obj = socketClient.transMessage(rpcRequest);//响应结果return obj;}
}
/*** 代理服务*/
public class ProxyDishService {public  <T> T  getInstance(Class<T> clazz){return (T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class<?>[]{clazz},new CuihuaInvocationHandler("localhost",8000));}
}
public class SocketClient {private String host;private int port;public SocketClient(String host,int port){this.host = host;this.port = port;}public Socket getSocket() throws IOException {Socket socket = new Socket(host,port);return socket;}public Object transMessage(RpcRequest request){ObjectOutputStream objectOutputStream = null;ObjectInputStream objectInputStream = null;try {Socket socket = getSocket();//将RpcRequest 写入到输出流中,通过socket传递给服务端objectOutputStream = new ObjectOutputStream(socket.getOutputStream());objectOutputStream.writeObject(request);objectOutputStream.flush();//通过输入流,读取服务端通过socket返回的结果objectInputStream = new ObjectInputStream(socket.getInputStream());Object obj = objectInputStream.readObject();return obj;}catch(Exception e){e.printStackTrace();}finally{try {objectInputStream.close();objectOutputStream.close();} catch (IOException e) {e.printStackTrace();}}return null;}
}
public class App 
{public static void main( String[] args ){//调用代理ProxyDishService proxy = new ProxyDishService();RequestDTO dto = new RequestDTO();dto.setColdOrHot("hot");dto.setSpicy(true);dto.setQuantityType("big");String responseStr = proxy.getInstance(DishService.class).servePickedChineseCabbage(dto);System.out.println("响应结果:"+responseStr);}
}

执行 cuihua-core 中 core-service 下的 App 的main方法,启动 ServerSocket;
然后,执行cuihua-snack 中 App 的 main方法,socket客户端发起调用。
服务端打印日志如下:

RequestDTO(quantityType=big, spicy=true, coldOrHot=hot)

客户端打印日志如下:

响应结果:Please wait a moment! The dish you want will come soon!

以上就是 《使用 Socket和动态代理以及反射 实现一个简易的 RPC 调用》的全部内容,感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/874600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux网络】epoll模型构建Reactor_Tcp服务器{协议/客户端/bind/智能指针}

文章目录 1.std::enable_shared_from_this<TcpServer>2.std::bind3.std::make_shared4.std::shared_ptrstd::shared_ptr 和 std::weak_ptr配合使用 5.剖析代码6.整体代码Calculator.hppClientCal.ccCMakeLists.txtCommon.hppEpoller.hppLog.hppMain.ccnocopy.hppProtocol…

YOLOv8预测时报错ValueError

【问题描述】执行YOLOv8预测代码时&#xff1a; # 导入训练好的权重文件做预测 from ultralytics import YOLO# Load a pretrained YOLOv8n model model YOLO("/data/yolov8/runs/detect/train6/weights/best.pt")# Run inference on bus.jpg with arguments model…

四大引用——强软弱虚

目录 一、强引用 二、软引用 三、弱引用 四、虚引用 一、强引用 强引用是在程序代码之中普遍存在的&#xff0c;类似于“Object obj new Object()”&#xff0c;obj变量引用Object这个对象&#xff0c;就叫做强引用。当内存空间不足&#xff0c;Java虚拟机宁愿抛出OutOfMe…

使用 Redis 实现验证码、token 的存储,用自定义拦截器完成用户认证、并使用双重拦截器解决 token 刷新的问题

基于session实现登录流程 1.发送验证码 用户在提交手机号后&#xff0c;会校验手机号是否合法&#xff0c;如果不合法&#xff0c;则要求用户重新输入手机号 如果手机号合法&#xff0c;后台此时生成对应的验证码&#xff0c;同时将验证码进行保存&#xff0c;然后再通过短信…

安防视频监控EasyCVR视频汇聚平台修改配置后无法启动的原因排查与解决

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台基于云边端一体化架构&#xff0c;兼容性强、支持多协议接入&#xff0c;包括国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SD…

Linux学习第55天:Linux 4G 通信实验(更快、更高、更强)

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 无论是有线网络还是WiFi都是摆脱不了布线的尴尬&#xff0c;而4G通信可以彻底拜托网线的束缚&#xff0c;实现无线网络通信。 而说到4G就不得不提到5G&#xff0c;中…

关于css中flex布局垂直居中失效问题的原因

项目中遇到用flex进行页面布局后&#xff0c;使用上下居中设置&#xff1a;align-item: center; 目标效果如下&#xff1a; 但是失效&#xff0c;不起作用&#xff0c;如下图所示&#xff1a; 各种排查过后发现设置了子模块 align-self 属性&#xff0c;这会覆盖容器上的 al…

mysql高阶语句:

mysql高阶语句&#xff1a; 高级语法的查询语句&#xff1a; select * from 表名 where limitsdistinct 去重查询like 模糊查询 排序语法&#xff1a;关键字排序 升序和降序 默认的排序方式就是升序 升序&#xff1a;ASC 配合order by语法 select * from 表名…

Python爬虫掌握-----4实战(爬取视频)

我们使用爬虫时难免会遇到爬取视频的情况&#xff0c;其实爬取图片视频&#xff0c;内容都是一样的。这里以b站视频为例。 一、开始 1.找到url&#xff0c;请求url 防盗链&#xff0c;需要写在UA伪装中 正常的三步&#xff1a; 1.url 2.requests请求 3.UA伪装 import req…

Zabbix基本介绍

文章目录 一、监控为什么需要监控需要监控什么Zabbix使用场景及系统概述zabbix介绍Zabbix功能Zabbix架构Zabbix术语 二、部署安装编译安装 一、监控 为什么需要监控 监控功能 在需要的时刻&#xff0c;提前预警即将出问题,避免故障发生。实时监控系统和业务,当出问题之后&am…

数据库安全:MySQL安全配置,MySQL安全基线检查加固

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 这一章节我们需…

配置Linux客户端免密登录服务端Linux主机的root用户

1.安装shh服务 首先安装shh服务&#xff0c;redhat端通过下面代码进行安装服务 sudo yum install sshd sudo yum install openssh-server 2.生成密钥&#xff08;公钥&#xff0b;私钥&#xff09; 执行ssh-keygen命令&#xff0c;会生成id_rsa&#xff08;私钥&#xff0…

并发编程--synchronized介绍

1.初步认识synchronized 先来看下利用 synchronized 实现 同步的基 础 &#xff1a; Java 中的每一个 对 象都可以作 为锁 。具体表 现 为 以下 3 种形式。 &#xff1a; 对于普通同步方法&#xff0c; 锁 是当前 实 例 对 象。 对于静 态 同步方法&#xff0c; 锁 是当前 类…

python-首字母移位(PythonTip)

[题目描述] 编写一个程序&#xff0c;将句子中每个单词的首字母移位到下一个单词。定义函数shift_first_letter()&#xff0c;参数为sentence&#xff08;字符串&#xff09;。在函数内&#xff0c;将句子中每个单词的首字母移位到下一个单词。最后一个单词的首字母移位到句子的…

SQL 注入漏洞详解 - Union 注入

1)漏洞简介 SQL 注入简介 SQL 注入 即是指 Web 应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在 Web 应用程序中事先定义好的查询语句的结尾上添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,…

记录|C#+winform创建扁平化风格界面

本项目的C#内容是自己跟做的&#xff0c;自己做的内容已经打包&#xff0c;可以通过自己跟做写的Dashboard界面&#xff0c;C#下的winform模式下载获得&#xff0c;但是需要花费3个积分 目录 前言一、左边设置和步骤界面步骤Step1.Step2.Step3.Step4Step5 二、右边属性和步骤属…

【BUG】已解决:ModuleNotFoundError: No module named ‘requests‘

ModuleNotFoundError: No module named ‘requests‘ 目录 ModuleNotFoundError: No module named ‘requests‘ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&a…

Python怎样读取URL生成PDF

1. 安装依赖的exe 需要在这个网址&#xff0c;安装一个exe包&#xff0c;地址&#xff1a;https://wkhtmltopdf.org/ 进入网址后&#xff0c;点这个位置&#xff1a; 选择一个你的操作系统的下载链接&#xff1a; 安装后的exe文件&#xff1a; C:\Program Files\wkhtmltopdf…

记录解决springboot项目上传图片到本地,在html里不能回显的问题

项目场景&#xff1a; 项目场景&#xff1a;在我的博客系统里&#xff1a;有个相册模块&#xff1a;需要把图片上传到项目里&#xff0c;在html页面上显示 解决方案 1.建一个文件夹 例如在windows系统下。可以在项目根目录下建个photos文件夹&#xff0c;把上传的图片文件…

华为OD2024D卷机试题汇总,含D量50%+,按算法分类刷题,事半功倍

目录 专栏导读华为OD机试算法题太多了&#xff0c;知识点繁杂&#xff0c;如何刷题更有效率呢&#xff1f; 一、逻辑分析二、数据结构1、线性表① 数组② 双指针 2、map与list3、队列4、链表5、栈6、滑动窗口7、二叉树8、并查集9、矩阵 三、算法1、基础算法① 贪心思维② 二分查…