开发一个简易的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);
        }
    }
}
相关推荐
晚风吹长发5 小时前
Docker基础——Docker Network(网络详解)
linux·运维·网络·ubuntu·docker·容器
hz567895 小时前
音视频SDK核心能力分析:低延迟传输与高并发接入方案
网络·安全·音视频·实时音视频·信息与通信
q567315235 小时前
企业级 HTTP 代理采购选型:技术评估清单 15 项
开发语言·网络·爬虫·网络协议·http·隧道ip·代理ip
白嫖一茶5 小时前
HTTP 状态码详解:五大类与常见状态码解析
网络·网络协议·http
treesforest8 小时前
如何解决IP定位精度不足导致的投放偏差
网络·网络协议·tcp/ip·ip属地·查ip归属地
茯苓gao9 小时前
嵌入式开发笔记:CAN与CAN FD完全指南——从帧格式差异到MCU选型实战
网络·笔记·stm32·嵌入式硬件·学习·汽车
奥莱维10 小时前
酒店客控系统与消防系统联动设计
网络
2401_8685347810 小时前
《论单元测试及其应用》
网络·网络协议
小此方10 小时前
Linux网络(一):揭秘从网络发展哲学到 TCP/IP 协议栈分层设计的设计哲学
linux·网络·tcp/ip
星野爱89510 小时前
远程控制哪家安全性更高?ToDesk、UU远程、向日葵隐私屏深度测评!
linux·运维·网络