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

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

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

前面的内容可以笔者的看第一篇笔记

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

引用:

1. 简易版 RPC 框架开发

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

RPC框架的简单理解

1.项目结构

 2.项目运行原理及调试过程

RpcServerExample类(服务器)

package com.yupi.yurpc.example;import com.yupi.yurpc.registry.LocalRegistry;
import com.yupi.yurpc.server.HttpServer;
import com.yupi.yurpc.server.VertxHttpServer;import java.util.Scanner;/*** RPC 服务器示例**/
public class RpcServerExample {public static void main(String[] args) {// 注册服务LocalRegistry.register(UserService.class.getName(), UserServiceImpl.class);// 获取端口号int port = getPort(args);System.out.println(" 启动RPC服务器...");System.out.println(" 已注册服务: " + UserService.class.getName());// 启动 web 服务HttpServer httpServer = new VertxHttpServer();httpServer.doStart(port);// 保持服务器运行System.out.println(" 服务器运行中,按 Ctrl+C 停止...");try {Thread.currentThread().join();} catch (InterruptedException e) {System.out.println(" 服务器已停止");}}/*** 获取端口号*/private static int getPort(String[] args) {int defaultPort = 8080;// 从命令行参数获取端口if (args.length > 0) {try {int port = Integer.parseInt(args[0]);if (port > 0 && port < 65536) {return port;}} catch (NumberFormatException e) {System.err.println("️  无效的端口号: " + args[0] + ",使用默认端口: " + defaultPort);}}// 如果端口被占用,尝试其他端口Scanner scanner = new Scanner(System.in);System.out.print("🔧 请输入端口号 (默认 " + defaultPort + "): ");String input = scanner.nextLine().trim();if (!input.isEmpty()) {try {int port = Integer.parseInt(input);if (port > 0 && port < 65536) {return port;}} catch (NumberFormatException e) {System.err.println("  无效的端口号,使用默认端口: " + defaultPort);}}return defaultPort;}
} 

启动服务端

注册服务

RpcServerExample类


// 注册服务
LocalRegistry.register(UserService.class.getName(), UserServiceImpl.class);

  • UserService.class.getName()
    获取接口 UserService 的全限定类名(如 com.example.UserService),作为服务的唯一标识 Key。

  • UserServiceImpl.class
    接口 UserService 的具体实现类(需实现该接口)。

  • LocalRegistry.register()
    将接口与实现类绑定到内存中的注册表(通常是 Map<String, Class<?>> 结构)。

将服务标识和具体实现类绑定

 LocalRegistry类(本地注册中心)

package com.yupi.yurpc.registry;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** 本地注册中心*/
public class LocalRegistry {/*** 注册信息存储*/private static final Map<String, Class<?>> map = new ConcurrentHashMap<>();/*** 注册服务** @param serviceName* @param implClass*/public static void register(String serviceName, Class<?> implClass) {map.put(serviceName, implClass);}/*** 获取服务** @param serviceName* @return*/public static Class<?> get(String serviceName) {return map.get(serviceName);}/*** 删除服务** @param serviceName*/public static void remove(String serviceName) {map.remove(serviceName);}
}

注册服务的实现

public static void register(String serviceName, Class<?> implClass) {map.put(serviceName, implClass); // 基础注册逻辑
}
组件说明
map静态注册表(通常为 Map<String, Class<?>> 类型)
serviceName服务标识(建议使用接口全限定名)
implClass服务实现类(需实现 serviceName 对应的接口)

将UserService接口与UserServiceImpl实现类绑定到内存中的注册表

UserService接口(用户服务接口)

package com.yupi.yurpc.example;/*** 用户服务接口*/
public interface UserService {/*** 获取用户信息** @param name 用户名* @return 用户信息*/String getUser(String name);/*** 计算两个数的和** @param a 第一个数* @param b 第二个数* @return 和*/int add(int a, int b);
} 

 UserServiceImpl (用户服务实现类)

(UserService接口的实现) 

package com.yupi.yurpc.example;/*** 用户服务实现类*/
public class UserServiceImpl implements UserService {@Overridepublic String getUser(String name) {return "Hello, " + name + "!";}@Overridepublic int add(int a, int b) {return a + b;}
} 

 LocalRegistry类绑定成功:

RpcServerExample类端口的获得

端口默认为8080

java.lang.IndexOutOfBoundsException: Invalid array range: 0 to 0 错误表示正在尝试访问或操作数组的一个无效范围。

错误的核心原因是:尝试在数组或集合上执行一个范围操作(如复制、切片等),但指定的范围(0到0)对于当前数据结构是无效的

这里无需在意

 然后从命令行参数获取端口(这里没有开命令行,所以会直接跳过)

如果端口被占用,尝试其他端口

笔者的8080端口确实被占用了,所以使用的为9090

然后就是对输入和端口的处理直接跳过了

下面的调试图为实现后的展示

判断输入是否为空,如果不是就可以进行下面的判断了

 这里的判断比较简单,就是判断端口是否合理。如果合理则返回,否则返回报错和提示语句。

直接跳过了

 然后就是返回注册成功的提示

 下一步启动注册服务

 VertxHttpServer类(Vertx HTTP 服务器)

继承了HttpServer接口

package com.yupi.yurpc.server;import io.vertx.core.Vertx;/*** Vertx HTTP 服务器*/
public class VertxHttpServer implements HttpServer {/*** 启动服务器** @param port*/public void doStart(int port) {// 创建 Vert.x 实例Vertx vertx = Vertx.vertx();// 创建 HTTP 服务器io.vertx.core.http.HttpServer server = vertx.createHttpServer();// 监听端口并处理请求server.requestHandler(new HttpServerHandler());// 启动 HTTP 服务器并监听指定端口server.listen(port, result -> {if (result.succeeded()) {System.out.println(" RPC服务器启动成功,监听端口: " + port);System.out.println(" 服务器地址: http://localhost:" + port);} else {System.err.println(" 服务器启动失败: " + result.cause().getMessage());System.err.println(" 请尝试以下解决方案:");System.err.println("   1. 检查端口 " + port + " 是否被其他程序占用");System.err.println("   2. 尝试使用其他端口号");System.err.println("   3. 以管理员权限运行程序");System.exit(1);}});}
}

  HttpServer接口(HTTP 服务器接口)

package com.yupi.yurpc.server;/*** HTTP 服务器接口*/
public interface HttpServer {/*** 启动服务器** @param port*/void doStart(int port);
}

监听端口并且处理请求

HttpServerHandler类( 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();httpServe

启动服务并且监听端口

 RpcRequest类(RPC 请求)

package com.yupi.yurpc.model;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** RPC 请求*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RpcRequest implements Serializable {/*** 服务名称*/private String serviceName;/*** 方法名称*/private String methodName;/*** 参数类型列表*/private Class<?>[] parameterTypes;/*** 参数列表*/private Object[] args;}

  RpcResponse类( RPC 响应)

package com.yupi.yurpc.model;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** RPC 响应*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RpcResponse implements Serializable {/*** 响应数据*/private Object data;/*** 响应数据类型(预留)*/private Class<?> dataType;/*** 响应信息*/private String message;/*** 异常信息*/private Exception exception;}

测试用例,JDK序列化和服务代理(JDK 动态代理)下次分析

下面是代码

RpcClientExample类( RPC 客户端示例)

package com.yupi.yurpc.example;import com.yupi.yurpc.proxy.ServiceProxyFactory;import java.util.Scanner;/*** RPC 客户端示例*/
public class RpcClientExample {public static void main(String[] args) {// 配置服务器地址configureServerUrl(args);System.out.println("连接到RPC服务器: " + System.getProperty("rpc.server.url", "http://localhost:8080"));System.out.println("开始RPC调用测试...");// 获取代理对象UserService userService = ServiceProxyFactory.getProxy(UserService.class);try {// 调用方法System.out.println("\n 测试 getUser 方法:");String result1 = userService.getUser("张三");System.out.println(" getUser result: " + result1);System.out.println("\n 测试 add 方法:");int result2 = userService.add(7, 2);System.out.println(" add result: " + result2);System.out.println("\n 所有测试通过!");} catch (Exception e) {System.err.println(" RPC调用失败: " + e.getMessage());System.err.println(" 请确保服务器已启动并且地址正确");}}/*** 配置服务器地址*/private static void configureServerUrl(String[] args) {String defaultUrl = "http://localhost:8080";// 从命令行参数获取服务器地址if (args.length > 0) {String url = args[0];if (url.startsWith("http://") || url.startsWith("https://")) {System.setProperty("rpc.server.url", url);return;} else {// 如果只提供了端口号,构造完整URLtry {int port = Integer.parseInt(url);System.setProperty("rpc.server.url", "http://localhost:" + port);return;} catch (NumberFormatException e) {System.err.println(" 无效的服务器地址: " + url);}}}// 交互式配置Scanner scanner = new Scanner(System.in);System.out.print("🔧 请输入服务器地址 (默认 " + defaultUrl + "): ");String input = scanner.nextLine().trim();if (!input.isEmpty()) {if (input.startsWith("http://") || input.startsWith("https://")) {System.setProperty("rpc.server.url", input);} else {try {int port = Integer.parseInt(input);System.setProperty("rpc.server.url", "http://localhost:" + port);} catch (NumberFormatException e) {System.err.println("  无效的地址,使用默认地址: " + defaultUrl);System.setProperty("rpc.server.url", defaultUrl);}}} else {System.setProperty("rpc.server.url", defaultUrl);}}
} 

ServiceProxy(服务代理(JDK 动态代理))

package com.yupi.yurpc.proxy;import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.yupi.yurpc.model.RpcRequest;
import com.yupi.yurpc.model.RpcResponse;
import com.yupi.yurpc.serializer.JdkSerializer;
import com.yupi.yurpc.serializer.Serializer;import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** 服务代理(JDK 动态代理)*/
public class ServiceProxy implements InvocationHandler {/*** 调用代理** @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 指定序列化器Serializer serializer = new JdkSerializer();// 构造请求RpcRequest rpcRequest = RpcRequest.builder().serviceName(method.getDeclaringClass().getName()).methodName(method.getName()).parameterTypes(method.getParameterTypes()).args(args).build();try {// 序列化byte[] bodyBytes = serializer.serialize(rpcRequest);// 发送请求// todo 注意,这里地址被硬编码了(需要使用注册中心和服务发现机制解决)String serverUrl = System.getProperty("rpc.server.url", "http://localhost:8080");try (HttpResponse httpResponse = HttpRequest.post(serverUrl).body(bodyBytes).execute()) {byte[] result = httpResponse.bodyBytes();// 反序列化RpcResponse rpcResponse = serializer.deserialize(result, RpcResponse.class);if (rpcResponse.getException() != null) {throw new RuntimeException("RPC调用异常: " + rpcResponse.getMessage(), rpcResponse.getException());}return rpcResponse.getData();}} catch (IOException e) {throw new RuntimeException("网络请求异常", e);}}
}

ServiceProxyFactory类( 服务代理工厂(用于创建代理对象)) 

package com.yupi.yurpc.proxy;import java.lang.reflect.Proxy;/*** 服务代理工厂(用于创建代理对象)*/
public class ServiceProxyFactory {/*** 根据服务类获取代理对象** @param serviceClass* @param <T>* @return*/public static <T> T getProxy(Class<T> serviceClass) {return (T) Proxy.newProxyInstance(serviceClass.getClassLoader(),new Class[]{serviceClass},new ServiceProxy());}
}

JdkSerializer类(JDK 序列化器) 

package com.yupi.yurpc.serializer;import java.io.*;/*** JDK 序列化器** @author <a href="https://github.com/liyupi">程序员鱼皮</a>* @learn <a href="https://codefather.cn">编程宝典</a>* @from <a href="https://yupi.icu">编程导航知识星球</a>*/
public class JdkSerializer implements Serializer {/*** 序列化** @param object* @param <T>* @return* @throws IOException*/@Overridepublic <T> byte[] serialize(T object) throws IOException {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream)) {objectOutputStream.writeObject(object);return outputStream.toByteArray();}}/*** 反序列化** @param bytes* @param type* @param <T>* @return* @throws IOException*/@Overridepublic <T> T deserialize(byte[] bytes, Class<T> type) throws IOException {ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);try {return (T) objectInputStream.readObject();} catch (ClassNotFoundException e) {throw new RuntimeException(e);} finally {objectInputStream.close();}}
}

 Serializer类( 序列化器接口) 

package com.yupi.yurpc.serializer;import java.io.IOException;/*** 序列化器接口** @author <a href="https://github.com/liyupi">程序员鱼皮</a>* @learn <a href="https://codefather.cn">编程宝典</a>* @from <a href="https://yupi.icu">编程导航知识星球</a>*/
public interface Serializer {/*** 序列化** @param object* @param <T>* @return* @throws IOException*/<T> byte[] serialize(T object) throws IOException;/*** 反序列化** @param bytes* @param type* @param <T>* @return* @throws IOException*/<T> T deserialize(byte[] bytes, Class<T> type) throws IOException;
}

状态分析

# Yu-RPC-Easy 状态图## 1. 服务器生命周期状态图```mermaid
stateDiagram-v2[*] --> 初始化初始化 --> 服务注册 : 注册服务服务注册 --> 启动中 : 启动HTTP服务器启动中 --> 运行中 : 服务器启动成功启动中 --> 启动失败 : 端口被占用/其他错误启动失败 --> 初始化 : 重新配置运行中 --> 处理请求 : 接收HTTP请求处理请求 --> 请求解析 : 读取请求体请求解析 --> 服务查找 : 反序列化成功请求解析 --> 错误响应 : 反序列化失败服务查找 --> 方法调用 : 服务存在服务查找 --> 服务未找到 : 服务不存在方法调用 --> 响应封装 : 调用成功方法调用 --> 异常处理 : 调用失败响应封装 --> 响应发送 : 序列化成功异常处理 --> 响应发送 : 封装异常信息错误响应 --> 响应发送服务未找到 --> 响应发送响应发送 --> 运行中 : 等待下一个请求运行中 --> 关闭中 : 收到关闭信号关闭中 --> 已关闭 : 清理完成已关闭 --> [*]
```## 2. 客户端代理状态图```mermaid
stateDiagram-v2[*] --> 代理创建代理创建 --> 等待调用 : 代理对象创建成功等待调用 --> 方法拦截 : 客户端调用方法方法拦截 --> 请求构建 : 获取方法信息请求构建 --> 序列化 : 构造RpcRequest序列化 --> 网络发送 : 序列化成功序列化 --> 序列化失败 : 序列化异常网络发送 --> 等待响应 : 发送成功网络发送 --> 网络异常 : 连接失败等待响应 --> 响应接收 : 收到服务器响应等待响应 --> 超时异常 : 响应超时响应接收 --> 反序列化 : 读取响应数据反序列化 --> 结果返回 : 反序列化成功反序列化 --> 反序列化失败 : 反序列化异常结果返回 --> 等待调用 : 返回给客户端序列化失败 --> 异常返回 : 抛出RuntimeException网络异常 --> 异常返回超时异常 --> 异常返回反序列化失败 --> 异常返回异常返回 --> 等待调用
```## 3. 注册中心状态图```mermaid
stateDiagram-v2[*] --> 注册中心初始化注册中心初始化 --> 等待注册 : 创建ConcurrentHashMap等待注册 --> 服务注册 : 收到注册请求服务注册 --> 注册成功 : 存储成功服务注册 --> 注册失败 : 存储异常注册成功 --> 等待注册 : 继续等待注册失败 --> 等待注册 : 继续等待等待注册 --> 服务查找 : 收到查找请求服务查找 --> 服务存在 : 找到服务服务查找 --> 服务不存在 : 未找到服务服务存在 --> 等待注册 : 返回服务类服务不存在 --> 等待注册 : 返回null等待注册 --> 服务注销 : 收到注销请求服务注销 --> 注销成功 : 删除成功服务注销 --> 注销失败 : 删除异常注销成功 --> 等待注册 : 继续等待注销失败 --> 等待注册 : 继续等待
```## 4. 序列化器状态图```mermaid
stateDiagram-v2[*] --> 序列化器初始化序列化器初始化 --> 等待序列化 : 创建序列化器实例等待序列化 --> 序列化处理 : 收到序列化请求序列化处理 --> 序列化成功 : 序列化完成序列化处理 --> 序列化失败 : 序列化异常序列化成功 --> 等待序列化 : 返回字节数组序列化失败 --> 异常处理 : 抛出IOException异常处理 --> 等待序列化 : 继续等待等待序列化 --> 反序列化处理 : 收到反序列化请求反序列化处理 --> 反序列化成功 : 反序列化完成反序列化处理 --> 反序列化失败 : 反序列化异常反序列化成功 --> 等待序列化 : 返回对象反序列化失败 --> 异常处理 : 抛出IOException
```## 5. HTTP请求处理状态图```mermaid
stateDiagram-v2[*] --> 请求接收请求接收 --> 请求验证 : 接收HTTP请求请求验证 --> 请求有效 : 验证通过请求验证 --> 请求无效 : 验证失败请求有效 --> 请求解析 : 开始解析请求解析 --> 解析成功 : 解析完成请求解析 --> 解析失败 : 解析异常解析成功 --> 服务处理 : 开始处理服务处理 --> 处理成功 : 处理完成服务处理 --> 处理失败 : 处理异常处理成功 --> 响应构建 : 构建响应处理失败 --> 错误响应 : 构建错误响应解析失败 --> 错误响应请求无效 --> 错误响应响应构建 --> 响应发送 : 发送响应错误响应 --> 响应发送响应发送 --> 请求完成 : 响应发送完成请求完成 --> [*]
```## 6. 异常处理状态图```mermaid
stateDiagram-v2[*] --> 正常运行正常运行 --> 网络异常 : 网络连接失败正常运行 --> 序列化异常 : 序列化失败正常运行 --> 服务异常 : 服务调用失败正常运行 --> 超时异常 : 请求超时网络异常 --> 重试机制 : 尝试重试重试机制 --> 重试成功 : 重试成功重试机制 --> 重试失败 : 重试次数用完重试成功 --> 正常运行 : 恢复正常重试失败 --> 异常返回 : 返回网络错误序列化异常 --> 异常返回 : 返回序列化错误服务异常 --> 异常返回 : 返回服务错误超时异常 --> 异常返回 : 返回超时错误异常返回 --> 正常运行 : 等待下一个请求
```## 7. 连接池状态图```mermaid
stateDiagram-v2[*] --> 连接池初始化连接池初始化 --> 空闲状态 : 创建连接池空闲状态 --> 获取连接 : 客户端请求连接获取连接 --> 连接可用 : 有可用连接获取连接 --> 创建连接 : 无可用连接连接可用 --> 使用中 : 分配连接创建连接 --> 连接创建成功 : 创建成功创建连接 --> 连接创建失败 : 创建失败连接创建成功 --> 使用中 : 使用新连接连接创建失败 --> 连接失败 : 返回错误使用中 --> 请求处理 : 处理HTTP请求请求处理 --> 响应完成 : 请求处理完成响应完成 --> 释放连接 : 释放连接释放连接 --> 空闲状态 : 连接回到池中连接失败 --> 空闲状态 : 继续等待
```## 8. 性能监控状态图```mermaid
stateDiagram-v2[*] --> 监控初始化监控初始化 --> 监控运行 : 启动监控监控运行 --> 请求开始 : 收到请求请求开始 --> 请求处理中 : 开始处理请求处理中 --> 请求完成 : 处理完成请求处理中 --> 请求超时 : 处理超时请求完成 --> 统计更新 : 更新统计信息请求超时 --> 统计更新 : 更新超时统计统计更新 --> 监控运行 : 继续监控监控运行 --> 性能告警 : 性能指标异常性能告警 --> 监控运行 : 继续监控监控运行 --> 监控停止 : 停止监控监控停止 --> [*]
```## 9. 服务发现状态图```mermaid
stateDiagram-v2[*] --> 服务发现初始化服务发现初始化 --> 等待发现 : 初始化完成等待发现 --> 服务查找 : 收到查找请求服务查找 --> 本地查找 : 在本地注册中心查找本地查找 --> 服务存在 : 找到服务本地查找 --> 服务不存在 : 未找到服务服务存在 --> 服务可用 : 服务可用服务存在 --> 服务不可用 : 服务不可用服务可用 --> 返回服务 : 返回服务信息服务不可用 --> 服务不存在 : 标记为不存在服务不存在 --> 返回空 : 返回null返回服务 --> 等待发现 : 继续等待返回空 --> 等待发现 : 继续等待
```## 10. 配置管理状态图```mermaid
stateDiagram-v2[*] --> 配置初始化配置初始化 --> 默认配置 : 加载默认配置默认配置 --> 配置验证 : 验证配置配置验证 --> 配置有效 : 验证通过配置验证 --> 配置无效 : 验证失败配置有效 --> 配置应用 : 应用配置配置应用 --> 配置完成 : 配置应用成功配置完成 --> 运行中 : 开始运行配置无效 --> 配置修复 : 修复配置配置修复 --> 配置验证 : 重新验证运行中 --> 配置更新 : 收到配置更新配置更新 --> 配置验证 : 验证新配置运行中 --> 配置完成 : 程序结束配置完成 --> [*]
``` 

流程图

# Yu-RPC-Easy 项目流程图## 1. 整体架构流程图```mermaid
graph TBA[客户端] --> B[代理对象]B --> C[序列化]C --> D[网络传输]D --> E[HTTP服务器]E --> F[请求处理]F --> G[服务发现]G --> H[反射调用]H --> I[序列化响应]I --> J[网络返回]J --> K[反序列化]K --> L[返回结果]M[服务注册] --> N[注册中心]G --> N
```## 2. 服务注册流程```mermaid
sequenceDiagramparticipant SP as 服务提供者participant RC as 注册中心participant SM as 服务管理器SP->>SM: 注册服务(serviceName, implClass)SM->>RC: register(serviceName, implClass)RC->>RC: 存储到ConcurrentHashMapRC-->>SM: 注册成功SM-->>SP: 注册完成
```## 3. 客户端调用流程```mermaid
sequenceDiagramparticipant Client as 客户端participant Proxy as 代理对象participant Serializer as 序列化器participant Network as 网络层participant Server as 服务器Client->>Proxy: 调用方法(method, args)Proxy->>Proxy: 构造RpcRequestProxy->>Serializer: 序列化请求Serializer-->>Proxy: 字节数组Proxy->>Network: 发送HTTP POSTNetwork->>Server: 传输请求Server->>Server: 处理请求Server-->>Network: 返回响应Network-->>Proxy: 接收响应Proxy->>Serializer: 反序列化响应Serializer-->>Proxy: RpcResponse对象Proxy-->>Client: 返回结果
```## 4. 服务端处理流程```mermaid
flowchart TDA[接收HTTP请求] --> B[读取请求体]B --> C[反序列化RpcRequest]C --> D{请求是否有效?}D -->|否| E[返回错误响应]D -->|是| F[从注册中心查找服务]F --> G{服务是否存在?}G -->|否| H[返回服务未找到]G -->|是| I[获取方法信息]I --> J[反射调用目标方法]J --> K{调用是否成功?}K -->|否| L[封装异常信息]K -->|是| M[封装返回结果]L --> N[序列化响应]M --> NN --> O[发送HTTP响应]E --> OH --> O
```## 5. 序列化流程```mermaid
graph LRA[对象] --> B[序列化器]B --> C[字节数组]C --> D[网络传输]D --> E[字节数组]E --> F[反序列化器]F --> G[对象]
```## 6. 异常处理流程```mermaid
flowchart TDA[发生异常] --> B{异常类型?}B -->|网络异常| C[重试机制]B -->|序列化异常| D[返回序列化错误]B -->|服务不存在| E[返回服务未找到]B -->|方法调用异常| F[返回调用异常]C --> G{重试次数?}G -->|未超限| H[重新发送请求]G -->|已超限| I[返回网络错误]H --> J{是否成功?}J -->|是| K[正常返回]J -->|否| GD --> L[客户端处理]E --> LF --> LI --> LK --> L
```## 7. 并发处理流程```mermaid
graph TBA[多个客户端请求] --> B[Vert.x事件循环]B --> C[异步处理请求1]B --> D[异步处理请求2]B --> E[异步处理请求N]C --> F[线程池执行]D --> FE --> FF --> G[并发访问注册中心]G --> H[ConcurrentHashMap]H --> I[返回处理结果]
```## 8. 启动流程```mermaid
sequenceDiagramparticipant App as 应用程序participant Registry as 注册中心participant Server as HTTP服务器participant Handler as 请求处理器App->>Registry: 注册服务Registry-->>App: 注册成功App->>Server: 启动服务器(port)Server->>Handler: 设置请求处理器Server->>Server: 监听端口Server-->>App: 服务器启动成功App->>App: 等待请求
```## 9. 关闭流程```mermaid
flowchart TDA[接收关闭信号] --> B[停止接收新请求]B --> C[等待当前请求完成]C --> D[关闭HTTP服务器]D --> E[清理注册中心]E --> F[释放资源]F --> G[程序退出]
```## 10. 性能监控流程```mermaid
graph LRA[请求开始] --> B[记录开始时间]B --> C[处理请求]C --> D[记录结束时间]D --> E[计算响应时间]E --> F[更新统计信息]F --> G[返回结果]
``` 

优势

优势说明
解耦调用方只需依赖接口,无需知道具体实现类
动态替换修改注册的实现类即可切换功能(如替换为 UserServiceMock.class 做测试)
集中管理所有服务绑定关系在注册中心统一维护

 对比远程注册中心

类型本地注册 (LocalRegistry)远程注册中心 (如 ZooKeeper/Nacos)
存储位置应用内存中独立中间件服务器
适用场景单机/进程内服务调用分布式跨进程服务发现
性能无网络开销,速度极快需网络通信,有延迟
服务发现直接通过接口名获取需从注册中心拉取服务地址列表

补充

register() 方法的核心作用

核心目的:建立 接口(抽象) 与 具体实现类 的映射关系,实现服务解耦。

典型方法签名:

public static void register(String serviceName, Class<?> implClass) {
    // 实现逻辑
}

参数解析:

参数类型作用示例
serviceNameString服务唯一标识 (通常用接口全限定名)"com.example.UserService"
implClassClass<?>接口的具体实现类UserServiceImpl.class

 map.put

public static void register(String serviceName, Class<?> implClass) {map.put(serviceName, implClass); // 基础注册逻辑
}
组件说明
map静态注册表(通常为 Map<String, Class<?>> 类型)
serviceName服务标识(建议使用接口全限定名)
implClass服务实现类(需实现 serviceName 对应的接口)

trim()

trim()是一个常用的字符串处理方法,用于移除字符串两端的空白字符。

端口号解析工具

int port = Integer.parseInt(input);

 用于将字符串输入转换为整数端口号

Vert.x实例

// 创建 Vert.x 实例
Vertx vertx = Vertx.vertx();// 创建 HTTP 服务器
io.vertx.core.http.HttpServer server = vertx.createHttpServer();
http://www.xdnf.cn/news/1205371.html

相关文章:

  • JavaScript:10个数组方法/属性
  • ROS2入门之开发环境搭建
  • 【C++】手搓一个STL风格的vector容器
  • vue如何在data里使用this
  • 屏幕晃动机cad【4张】三维图+设计说明书
  • Java面试宝典:MySQL8新特性
  • 软工八将:软件开发全流程核心角色体系解析
  • kubectl中的yaml配置详解
  • 【Unity游戏】——1.俄罗斯方块
  • 【大模型LLM】梯度累积(Gradient Accumulation)原理详解
  • 软件设计师-知识点记录
  • creating and using sequence
  • AI论文阅读方法+arixiv
  • Redis未授权访问的利用的几种方法原理以及条件
  • yolo 目标检测600类目标
  • STM32中集成USB驱动
  • STM32 USB HOST 驱动FT232 USB转串
  • Android 解析 TrafficDescriptor 的 OSAPP 信息
  • OpenLayers 综合案例-区域掩膜
  • [机缘参悟-237]:AI人工神经网络与人类的神经网络工作原理的相似性
  • SpringBoot数学实例:高等数学实战
  • 7.项目起步(1)
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现面部口罩的检测识别(C#代码,UI界面版)
  • 数据结构(动态数组)
  • HTML应用指南:利用GET请求获取全国小米之家门店位置信息
  • 第4章唯一ID生成器——4.2 单调递增的唯一ID
  • 【Zustand】从复杂到简洁:Zustand 状态管理简化实战指南
  • 绿算技术携手昇腾发布高性能全闪硬盘缓存设备,推动AI大模型降本增效
  • Laravel 分页方案整理
  • 安宝特新闻丨Vuzix与Wyr.Ai合作推出基于M400眼镜的全新一代质检平台