本文为笔者阅读鱼皮的项目 《简易版 RPC 框架开发》的笔记,如果有时间可以直接去看原文,

1. 简易版 RPC 框架开发

前面的内容可以笔者的前面几篇笔记

鱼皮项目简易版 RPC 框架开发(一)

鱼皮项目简易版 RPC 框架开发(二)

鱼皮项目简易版 RPC 框架开发(三)

引用:

1. 简易版 RPC 框架开发

鱼皮项目简易版 RPC 框架开发(一)

鱼皮项目简易版 RPC 框架开发(二)

鱼皮项目简易版 RPC 框架开发(三)

RPC框架的简单理解

HTTP 请求处理源代码 

package com.yupi.yurpc.server;import com.yupi.yurpc.model.RpcRequest;
import com.yupi.yurpc.model.RpcResponse;
import com.yupi.yurpc.registry.LocalRegistry;
import com.yupi.yurpc.serializer.JdkSerializer;
import com.yupi.yurpc.serializer.Serializer;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;import java.io.IOException;
import java.lang.reflect.Method;/*** HTTP 请求处理*/
public class HttpServerHandler implements Handler<HttpServerRequest> {@Overridepublic void handle(HttpServerRequest request) {// 指定序列化器final Serializer serializer = new JdkSerializer();// 记录日志System.out.println("Received request: " + request.method() + " " + request.uri());// 异步处理 HTTP 请求request.bodyHandler(body -> {byte[] bytes = body.getBytes();RpcRequest rpcRequest = null;try {rpcRequest = serializer.deserialize(bytes, RpcRequest.class);} catch (Exception e) {e.printStackTrace();}// 构造响应结果对象RpcResponse rpcResponse = new RpcResponse();// 如果请求为 null,直接返回if (rpcRequest == null) {rpcResponse.setMessage("rpcRequest is null");doResponse(request, rpcResponse, serializer);return;}try {// 获取要调用的服务实现类,通过反射调用Class<?> implClass = LocalRegistry.get(rpcRequest.getServiceName());if (implClass == null) {rpcResponse.setMessage("Service not found: " + rpcRequest.getServiceName());doResponse(request, rpcResponse, serializer);return;}Method method = implClass.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());Object result = method.invoke(implClass.newInstance(), rpcRequest.getArgs());// 封装返回结果rpcResponse.setData(result);rpcResponse.setDataType(method.getReturnType());rpcResponse.setMessage("ok");} catch (Exception e) {e.printStackTrace();rpcResponse.setMessage(e.getMessage());rpcResponse.setException(e);}// 响应doResponse(request, rpcResponse, serializer);});}/*** 响应* @param request* @param rpcResponse* @param serializer*/void doResponse(HttpServerRequest request, RpcResponse rpcResponse, Serializer serializer) {HttpServerResponse httpServerResponse = request.response().putHeader("content-type", "application/json");try {// 序列化byte[] serialized = serializer.serialize(rpcResponse);httpServerResponse.end(Buffer.buffer(serialized));} catch (IOException e) {e.printStackTrace();httpServerResponse.end(Buffer.buffer());}}
}

代码功能概述

这段代码实现了一个基于 HTTP 协议的 RPC 服务器请求处理器,负责接收客户端请求、反射调用本地服务方法并返回响应结果。核心功能包括请求反序列化、服务方法调用、结果封装和序列化响应。

核心组件分析

序列化器

  • 使用 JdkSerializer 进行请求和响应的序列化与反序列化。
  • doResponse 方法中将响应对象序列化为字节流。

请求处理流程

  • 通过 request.bodyHandler 异步处理请求体。
  • 将请求体字节流反序列化为 RpcRequest 对象。
  • 若反序列化失败,返回包含错误信息的响应。

服务调用机制

  • 通过 LocalRegistry.get() 根据服务名获取实现类。
  • 使用反射机制调用目标方法:implClass.getMethod() 获取方法,method.invoke() 执行调用。
  • 捕获调用过程中的异常并封装到响应中。

响应构建

  • 成功调用时设置方法返回值到 rpcResponse.data
  • 异常时设置异常信息到 rpcResponse.messagerpcResponse.exception

关键方法说明

handle()

  • 主处理方法,接收 HttpServerRequest 对象。
  • 采用异步非阻塞方式处理请求体。
  • 协调反序列化、服务调用和响应流程。

doResponse()

  • 设置 HTTP 响应头 content-type: application/json
  • RpcResponse 序列化为字节流写入响应体。
  • 异常时返回空缓冲区。

补充

JdkSerializer

JDK序列化是Java平台提供的一种对象序列化机制,通过java.io.Serializable接口实现。它允许将对象转换为字节流,便于存储或传输,并能在需要时重新构造为原始对象。

详细分析见:

鱼皮项目简易版 RPC 框架开发(三)

doResponse

序列化响应对象为字节流的方法

doResponse 方法中,将响应对象序列化为字节流通常涉及以下几个关键步骤:

使用 JSON 序列化库
常见的 JSON 序列化库如 JacksonGsonFastjson 可以将 Java 对象转换为 JSON 字符串,再进一步转为字节流。例如,使用 JacksonObjectMapper

ObjectMapper objectMapper = new ObjectMapper();
byte[] responseBytes = objectMapper.writeValueAsBytes(responseObject);

手动构建字节流
如果需要自定义格式,可以直接拼接字符串并调用 getBytes() 方法转换为字节流。例如:

String responseString = "{\"status\":\"success\",\"data\":" + customData + "}";
byte[] responseBytes = responseString.getBytes(StandardCharsets.UTF_8);

使用协议缓冲区(Protocol Buffers)
对于高性能场景,可以通过 Protocol Buffers 定义消息格式并生成字节流:

ResponseProto.Response response = ResponseProto.Response.newBuilder().setStatus("OK").setData(data).build();
byte[] responseBytes = response.toByteArray();

设置正确的 Content-Type 和编码
确保响应头中包含正确的 Content-Type 和字符编码(如 application/json; charset=UTF-8),以便客户端正确解析字节流。

处理异常情况
捕获序列化过程中可能抛出的异常(如 JsonProcessingException),并返回错误信息或默认响应。例如:

try {byte[] responseBytes = objectMapper.writeValueAsBytes(responseObject);// 发送字节流到输出流
} catch (JsonProcessingException e) {byte[] errorBytes = "{\"error\":\"Serialization failed\"}".getBytes();
}

优化性能
对于高频调用场景,可以复用序列化工具实例(如 ObjectMapper),避免重复创建对象带来的开销。

 printStackTrace

理解 printStackTrace 的作用

printStackTrace() 是 Java 中 Throwable 类的方法,用于将异常的堆栈跟踪信息输出到标准错误流(System.err)。它显示了异常的类型、消息以及从方法调用栈顶到底的完整路径,帮助开发者快速定位问题根源。

使用场景

  • 调试阶段:在开发或测试阶段,通过打印堆栈跟踪快速定位异常发生的代码位置。
  • 日志记录:结合日志框架(如 Log4j、SLF4J),将堆栈信息写入日志文件而非直接打印到控制台。

代码示例

try {// 可能抛出异常的代码int result = 10 / 0;
} catch (ArithmeticException e) {e.printStackTrace(); // 打印堆栈跟踪到 System.err
}

输出格式说明

堆栈跟踪通常包含以下内容:

  1. 异常类型:如 ArithmeticException
  2. 异常消息:如 / by zero
  3. 调用栈:从触发异常的方法到最外层的调用方法,每行显示类名、方法名、文件名和行号。

示例输出:

java.lang.ArithmeticException: / by zeroat com.example.Test.main(Test.java:10)

替代方案(生产环境推荐)

直接使用 printStackTrace() 在生产环境中可能不够灵活,建议:

  • 日志框架:通过 logger.error("Error occurred", e) 记录异常,支持分级存储和格式化。
  • 自定义输出:重定向堆栈跟踪到字符串或文件,例如:
    StringWriter sw = new StringWriter();
    e.printStackTrace(new PrintWriter(sw));
    String stackTrace = sw.toString();
    

注意事项

  • 性能影响:频繁调用 printStackTrace() 可能影响性能,尤其在循环或高频操作中。
  • 信息暴露:堆栈跟踪可能暴露敏感信息(如内部类名),需谨慎处理。

通过合理使用 printStackTrace() 或其替代方案,可以高效排查异常问题。

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

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

相关文章

力扣-79.单词搜索

题目链接 79.单词搜索 class Solution {int m, n;public boolean exist(char[][] board, String word) {m board.length;n board[0].length;boolean[][] visited new boolean[m][n];// 遍历网格中的每个单元格作为搜索起点for (int i 0; i < m; i) {for (int j 0; j …

LabVIEW的To More Specific Class功能说明

​To More Specific Class 是 LabVIEW 中用于控件引用类型转换的关键函数。可将通用 GObject 引用&#xff0c;精准转为 Listbox、TreeControl 等特定控件类引用&#xff0c;让开发者能调用专属属性&#xff08;如获取列表行数&#xff09;&#xff0c;实现对不同控件类的差异化…

Ubuntu20.04安装和配置Samba实现Win11下共享文件夹

Samba是在Linux和UNIX系统上实现 SMB / CIFS 协议的开源软件&#xff0c;主要用于局域网内的文件共享和打印服务。Samba通过SMB/CIFS协议实现跨平台资源共享&#xff0c;支持匿名用户和本地用户访问共享目录&#xff0c;客户端主要为Windows系统。其核心进程包括&#xff1a; ‌…

设计模式(八)结构型:桥接模式详解

设计模式&#xff08;八&#xff09;结构型&#xff1a;桥接模式详解桥接模式&#xff08;Bridge Pattern&#xff09;是 GoF 23 种设计模式中的结构型模式之一&#xff0c;其核心价值在于将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。它通过“组合”而非“继承”…

【边缘填充】——图像预处理(OpenCV)

目录 1 边界复制&#xff08;BORDER_REPLICATE&#xff09; 2 边界反射&#xff08;BOEDER_REFLECT&#xff09; 3 边界反射101&#xff08;BORDER_REFLECT101&#xff09; 4 边界常数&#xff08;BORDER_CONSTANT&#xff09; 5 边界包裹&#xff08;BORDER_WRAP&#xf…

git同步到github出错-几个问题-一天晚上(2025.7.29)

访问不了github 代理和加速器都正常&#xff0c;但是就是访问不了这个网站尝试过几种方法都不行&#xff0c;后面突然可以了。 之后发现一种情况会不行&#xff1a;同时开启 同步不了 http连接 https://blog.csdn.net/m0_73972962/article/details/146198392 一堆问题 ssh连接才…

Redis未授权访问的利用的几种方法原理以及条件

一、redis通过定时任务反弹shell1.利用条件&#xff1a;需要能够登录redis数据库&#xff0c;并且redis以root用户运行。同时/var/spool/cron目录要具有写和执行权限。二、Redis主从getshell1.原理&#xff1a;在Redis 4.x之后&#xff0c;Redis新增了模块功能&#xff0c;通过…

DNF 与 YUM 的区别详解:从 CentOS 7 到 CentOS 9 的演进

&#x1f365; DNF 与 YUM 的区别详解&#xff1a;从 CentOS 7 到 CentOS 9 的演进标签&#xff1a;CentOS、YUM、DNF、Linux 包管理、系统升级、兼容性 适用版本&#xff1a;CentOS 7、CentOS 8、CentOS 9&#x1f9e9; 一、背景介绍 CentOS 中使用的包管理工具是 RedHat 系列…

mp核心功能

条件构造器mybatisPlus支持各种复杂的where条件, 满足日常的开发wrapper类就是条件构造器提供了很多子类条件构造器的用法&#xff1a;QueryWrapper和LambdaQueryWrapper通常用来构建select、delete、update的where条件部分UpdateWrapper和LambdaUpdateWrapper通常只有在set语句…

pcm,msd调制解调仿真

PCM&#xff08;脉冲编码调制&#xff09;和MSD&#xff08;多符号差分&#xff09;调制解调系统的MATLAB仿真代码。 PCM (脉冲编码调制) 仿真 %% PCM调制解调仿真 clear; clc; close all;% 参数设置 Fs 8000; % 采样频率 (Hz) t_duration 0.02; % 信号持续时间 (秒…

【网络安全】信息网络安全建设方案(WORD)

1.1 安全整体架构 1.2 安全建设拓扑 1.3 安全建设内容与目标 2.1 用户侧安全建设思路 2.2 用户侧安全建设拓扑 2.3 用户侧安全建设内容 2.3.1 PKI 升级改造 2.3.2 安全防护 2.3.3 安全检测 2.3.4 安全管理 3.1 跨网安全访问与交换平台安全建设思…

微服务 01

微服务是一种软件架构风格&#xff0c;它是以专注于单一职责的很多小型项目为基础&#xff0c;组合出复杂的大型应用。 &#xff08;对应的是单体架构风格&#xff09; 一、认识微服务 1、单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打…

20250726让荣品的PRO-RK3566开发板使用TF卡启动

20250726让荣品的PRO-RK3566开发板使用TF卡启动 2025/7/26 8:58缘起&#xff1a;需要升级 荣品的PRO-RK3566核心板的 底板上的FPGA程序。 由于没有使用RK809的电量计功能&#xff0c;板子一上电就会被关机&#xff01;^_于是给生产线制作了一张TF卡/启动卡&#xff0c;插到底板…

Selenium使用指南

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 概述selenium是网页应用中最流行的自动化测试工具&#xff0c;可以用来做自动化测试或者浏览器爬虫等。官网地址为&#xff1a;相对于另外一款web自动化测试工具QT…

[机缘参悟-235]:通过AI人工升级网络的工作方式和特征理解人的思维方式

AI人工神经网络通过模拟生物神经元连接机制、构建层级化特征提取结构&#xff0c;并结合数据驱动的学习方式&#xff0c;为理解人类思维方式提供了技术参照框架&#xff0c;但其本质仍是基于统计的模式匹配&#xff0c;与人类意识层面的思维存在根本差异。以下从其工作方式、基…

【C#补全计划:类和对象(七)—— 重写虚方法】

一、virtual和override1. 问题引入&#xff1a;使用里氏替换原则时&#xff0c;使用父类容器装载子类对象&#xff0c;若不使用virtual和override而是使用new&#xff0c;当子类调用两个类共有的方法时&#xff0c;调用的是父类的方法而不是子类的方法&#xff1a;using System…

TCPIP之常用协议

一、TCPIP之网络支撑协议 1.ARP ARP是网络层协议&#xff0c;在同一广播域内&#xff0c;将IP地址解析成MAC地址. 1.1 无故ARP 请求型无故ARP 设备在网络中不管是自动获取ip地址还是手动配置ip地址&#xff0c;设备都会发送请求型无故ARP检查这个ip地址是否有重复的。 应…

网络之路24:VLAN基础实验

正文共&#xff1a;2345 字 18 图&#xff0c;预估阅读时间&#xff1a;3 分钟目录网络之路第一章&#xff1a;Windows系统中的网络0、序言1、Windows系统中的网络 1.1、桌面中的网卡 1.2、命令行中的网卡 1.3、路由表 1.4、家用路由器网络之路第二章&#xff1a;认识企业设备2…

基于Verilog的神经网络加速器设计

本设计实现了一个高效的神经网络加速器,专注于卷积神经网络(CNN)的核心计算功能。该设计具有以下创新点: 并行处理架构:同时处理多个卷积窗口,提高计算吞吐量 动态权重加载:支持运行时更新卷积核权重 流水线优化:卷积、激活、池化三级流水线设计 可配置参数:支持不同尺寸…

基于springboot的零食商城的设计与实现/零食销售系统的设计与实现

用户&#xff1a;注册&#xff0c;登录&#xff0c;商品信息&#xff0c;团购商品&#xff0c;公告资讯&#xff0c;后台管理&#xff0c;在线客服&#xff0c;购物车&#xff0c;个人中心管理员&#xff1a;登录&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商品类型…