开发一个简易的RPC框架

一、基础的概念

  • 负载均衡:将大量用户请求分摊到不同的服务器上处理,以提高系统整体的并发处理能力以及可靠性。
  • 容错机制:(如果服务器接口调用失败,该如何处理)为保证分布式系统的高可用,会给服务器的调用机制增加容错机制。如失败重试,降级调用其他接口等。

开发一个简易的RPC框架

项目初始化
  1. common:公共模块(会同时被消费者和提供者引用)

    基础的数据模型和服务相关的接口。

  2. provider:服务提供者模块(需要暴露接口,等待消费者调用)

  3. consumer:消费者模块(需要引入rpc和common依赖)

  4. easy-rpc:简易rpc框架

    ①请求处理器

java 复制代码
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> {

    @Override
    public 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 {
                // 对请求反序列化,消费者发送的数据是byte字节数组需要转为Java对象
                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());// 在注册中心获取服务名称
                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());
        }
    }
}

②请求类&响应类

java 复制代码
import java.io.Serializable;

/**
 * RPC 请求
 */
public class RpcRequest implements Serializable {

    /**
     * 服务名称
     */
    private String serviceName;

    /**
     * 方法名称
     */
    private String methodName;

    /**
     * 参数类型列表
     */
    private Class<?>[] parameterTypes;

    /**
     * 参数列表
     */
    private Object[] args;

    public String getServiceName() {
        return serviceName;
    }

    public RpcRequest(String serviceName, String methodName, Class<?>[] parameterTypes, Object[] args) {
        this.serviceName = serviceName;
        this.methodName = methodName;
        this.parameterTypes = parameterTypes;
        this.args = args;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Class<?>[] getParameterTypes() {
        return parameterTypes;
    }

    public void setParameterTypes(Class<?>[] parameterTypes) {
        this.parameterTypes = parameterTypes;
    }

    public Object[] getArgs() {
        return args;
    }

    public void setArgs(Object[] args) {
        this.args = args;
    }
}

响应类

java 复制代码
import java.io.Serializable;

/**
 * RPC 响应
 */
public class RpcResponse implements Serializable {

    /**
     * 响应数据
     */
    private Object data;

    /**
     * 响应数据类型(预留)
     */
    private Class<?> dataType;

    /**
     * 响应信息
     */
    private String message;

    /**
     * 异常信息
     */
    private Exception exception;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Class<?> getDataType() {
        return dataType;
    }

    public void setDataType(Class<?> dataType) {
        this.dataType = dataType;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Exception getException() {
        return exception;
    }

    public void setException(Exception exception) {
        this.exception = exception;
    }
}

③服务注册类

java 复制代码
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static java.util.Objects.nonNull;

/**
 * 本地注册器(理解为注册中心的作用)
 */
public class LocalRegistry {
    /**
     * 注册中心
     */
    private static final Map<String, Class<?>> registryMap = new ConcurrentHashMap<>();

    /**
     * 注册
     */
    public static void registry(String serviceName, Class<?> clazz) {
        registryMap.put(serviceName, clazz);
    }

    /**
     * 删除
     */
    public static void remove(String serviceName, Class<?> clazz) {
        registryMap.remove(serviceName);
    }

    /**
     * 获取
     */
    public static Class<?> get(String serviceName) {
        Class<?> aClass = registryMap.get(serviceName);
        if (nonNull(aClass)) {
            return aClass;
        }
        throw new RuntimeException("当前请求接口不存在:" + serviceName);
    }
}

④消费者的请求代理

java 复制代码
/**
 * 静态代理 调用服务提供者
 */
public class UserServiceProxy implements UserService {
    @Override
    public User getUser() {
        RpcRequest rpcRequest = new RpcRequest(UserService.class.getName(), "getUser", new Class[]{}, new Object[]{});
        Serializer serializer = new JdkSerializer();
        try {
            byte[] bytes = serializer.serialize(rpcRequest);
            HttpResponse response = HttpRequest.post("http://localhost:8099/").body(bytes).execute();
            RpcResponse rpcResponse = serializer.deserialize(response.bodyBytes(), RpcResponse.class);
            return (User) rpcResponse.getData();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
相关推荐
被摘下的星星10 分钟前
HTTP 状态码 和 网络端口号
网络·网络协议·http
云边云科技_云网融合10 分钟前
生物医疗跨院区影像与诊疗数据传输:高带宽与合规双重目标下的网络搭建指南
网络·科技
ESDWAN13 分钟前
企业组网后网络频繁掉线,常见故障排查指南
运维·网络·架构
崽崽..30 分钟前
大端存储和小端存储的区别以及与网络编程的联系
网络·大小端
迪康Defender1 小时前
终端安全实践:浅谈端点安全管理系统内置终端防火墙能力
运维·服务器·网络·经验分享·安全·php·终端安全管理
AI备忘录1 小时前
(二十二)华为华三锐捷迈普思科 802.1X 端口认证配置命令(网络准入五厂商对照)
运维·服务器·开发语言·网络·安全·华为
优化Henry1 小时前
LTE站点以太网光模块告警处理实践
运维·网络·笔记·学习·信息与通信
数字新视界1 小时前
2026机房动环监控选型指南:场景规模需求、市场发展占有率和竞争梯队报告解析
大数据·运维·网络·人工智能·嵌入式硬件·机房动环监控·机房环境安全
我不是程序员三三1 小时前
企业风控实战:文件外发控制软件如何补齐数据泄露的出口短板
网络
傲世仙尊1 小时前
序列化与自定义协议-把结构体拆成字节流再拼回来
linux·服务器·网络·arm开发