RPC - 自定义序列化器

序列化手段有很多,之前的代码中都是硬编码 Serializer s = new JdkSerializer(),其中 JdkSerializer 是自定义的基于 JDK 的序列化器 现在可以给用户更多选择,如 JSON、Hessian、Kryo 额外三个内置序列化器,以及基于 SPI 的自定义序列化器 内置序列化器 首先分别实现 JSON、Hessian、Kryo 的序列化类,这一步与项目本身无关,这里不放代码了 接着,为了更有效地区分序列化器的名称,可以创建一个枚举类或者接口类存储内置序列化器的名称: public interface SerializerKeys { String JDK = "jdk"; String JSON = "json"; String KRYO = "kryo"; String HESSIAN = "hessian"; } 序列化器明显可以复用,所以创建一个单例的序列化器工厂: public class SerializerFactory { // 单例,存储名称到序列化器实例的映射 private static final Map<String, Serializer> KEY_SERIALIZER_MAP = new HashMap<String, Serializer>() {{ put(SerializerKeys.JDK, new JdkSerializer()); put(SerializerKeys.JSON, new JsonSerializer()); put(SerializerKeys.KRYO, new KryoSerializer()); put(SerializerKeys.HESSIAN, new HessianSerializer()); }}; // 默认序列化器 private static final Serializer DEFAULT_SERIALIZER = KEY_SERIALIZER_MAP.get("jdk"); // 获取实例 public static Serializer getInstance(String key) { return KEY_SERIALIZER_MAP.getOrDefault(key, DEFAULT_SERIALIZER); } } 最后,不要忘记修改默认 Config 配置: ...

March 23, 2026

RPC - 配置文件与Mock

由于我设计的是一个 RPC 框架,这个框架的特点就是,同时具备作为一个服务器的功能和作为客户端的功能 服务器端:由 Provider 使用,启动一个 RPC 服务器并维护注册中心 客户端:由 Consumer 使用,提供动态代理类由 Consumer 调用服务 所以配置文件是必不可少的 另外,为了开发客户端侧的功能方便,可以顺便手动为框架设计一套 Mock,这样就无需每次调试都通过 Provider 启动 RPC 服务器了 配置文件 首先在框架内编写 RPC 框架的默认配置,以类的形式给出。这也是 Provider 启动 RPC 服务器或客户端无配置文件时会使用的默认配置: @Data public class RpcConfig { /** * 名称 */ private String name = "ficn-rpc"; /** * 版本号 */ private String version = "1.0"; /** * 服务器主机名 */ private String serverHost = "localhost"; /** * 服务器端口号 */ private Integer serverPort = 8080; /** * 是否使用模拟数据 */ private boolean mock = false; } 然后编写读取配置文件的工具类,这个工具类是用于服务器侧或客户端侧从 resources/application.properties 文件中读取用户配置的: ...

March 23, 2026

RPC框架简单实践

创建一个简单示例,原理如下: 运行一个RPC服务器,服务器中使用ConcurrentHashMap<String, Class>存储服务实现类的类名和实例 服务提供者Provider将自己的实现类加入该Map中去,实现服务注册 服务消费者Consumer发送HTTP的服务请求,其中包含服务类名、方法名、参数类型、参数列表四个参数 RPC服务器接收到服务请求,根据解析的请求内容到Map中取相对应的实例,通过反射执行对应方法 RPC服务器将执行方法后的结果封装到响应中返回Consumer 关于Consumer发送请求如果每次都手动构造请求体就太麻烦了,有两个实现: 编写静态的代理类,也实现了服务接口,实现内部是构造相应的请求体发送给RPC服务器,获取响应后反序列化结果返回 不过这个静态代理类需要针对每个服务接口方法硬编码请求体,比如.methodName(“getUser”)这种都要手动设置 编写动态代理类,可以基于JDK动态代理实现,这样就不用手动实现每个服务接口,invoke()方法会获取到各种调用参数信息,将这些信息封装好发送就行 共享接口 RPC服务器、服务提供者、服务消费者都需要得到服务接口信息,如此才能实例化或实现功能 用户User: public class User implements Serializable { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } 用户服务接口UserService: public interface UserService { /** * 获取用户 * * @param user * @return */ User getUser(User user); } RPC服务器 核心Handler中,先反序列化请求对象,从中取出请求的服务信息,从注册中心Map获取实现类实例后,通过反射执行方法,然后将执行结果封装为响应返回: public class HttpServerHandler implements Handler<HttpServerRequest> { @Override public void handle(HttpServerRequest request) { // 创建序列化器 final Serializer serializer = new JdkSerializer(); // 记录日志 System.out.println("Received request: " + request.method() + " " + request.uri()); // 异步处理请求 request.bodyHandler(body -> { byte[] bytes = body.getBytes(); RpcRequest rpcRequest = null; try { // 反序列化请求参数为RpcRequest对象 rpcRequest = serializer.deserialize(bytes, RpcRequest.class); } catch (Exception e) { e.printStackTrace(); } RpcResponse rpcResponse = new RpcResponse(); // 如果请求为空则返回错误信息 if (rpcRequest == null) { rpcResponse.setMessage("Invalid request, request is null"); doResponse(request, rpcResponse, serializer); return; } try { // 从请求取服务名,然后从注册中心获取服务实现类 Class<?> implClass = LocalRegistry.get(rpcRequest.getServiceName()); // 获取服务实现类的方法并执行 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); }); } private void doResponse(HttpServerRequest request, RpcResponse rpcResponse, Serializer serializer) { HttpServerResponse httpServerResponse = request.response().putHeader("content-type", "application/json"); try { // 序列化响应结果为字节数组 byte[] bytes = serializer.serialize(rpcResponse); // 发送响应 httpServerResponse.end(Buffer.buffer(bytes)); } catch (IOException e) { e.printStackTrace(); httpServerResponse.end(Buffer.buffer()); } } } 关于注册中心,维护该Map即可: ...

March 22, 2026