开发一个简易的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);
        }
    }
}
相关推荐
饮品爱好者9 小时前
[ 网络 ] NO.1 TCP/IP网络模型
网络·网络协议·tcp/ip
IT策士9 小时前
Docker 网络进阶:容器间通信与 DNS 解析
网络·docker·容器
小陶来咯10 小时前
agent × 豆包:端到端语音实时交互
网络·ai·机器人·bug·交互
艾莉丝努力练剑10 小时前
【Linux:文件】库的制作与原理进阶
linux·运维·服务器·网络·数据库·c++·人工智能
z2023050810 小时前
RDMA之RDMA 的发展原因和软件架构基础(10)
linux·服务器·网络·人工智能·ai
云边云科技_云网融合10 小时前
企业级网络智能运维体系构建:从被动响应到主动预判
大数据·网络·人工智能
VOOHU-沃虎10 小时前
音频变压器选型指南:阻抗匹配、隔离耐压与低失真设计的工程实践
网络·音频
努力成为AK大王10 小时前
网络层核心(四):路由协议与移动IP全解析
网络·智能路由器·路由选择协议
潜创微科技10 小时前
IT68051+IT6615:4K@60Hz HDMI+USB Over IP 网线延长方案|低延时 100 米无损传输
网络·网络协议·tcp/ip