美文网首页
实现简单的RPC框架

实现简单的RPC框架

作者: 侧耳倾听y | 来源:发表于2021-06-19 18:15 被阅读0次

仅实现最基本的功能

RPC原理

实现步骤

1. 本地代理存根

使用cglib获取代理Service

  • 在本地获取Service
OrderService orderService = ServiceFactory.create(OrderService.class, "http://localhost:8080/");
Order order = orderService.findByOrderNo("110");
log.info("rpc result:{}", order);
  • 获取Service的实现
public class ServiceFactory {

    static {
        ParserConfig.getGlobalInstance().addAccept("org.example");
    }

    public static  <T> T create(Class<T> serviceClass, String host) {
        ServiceInterceptor interceptor = new ServiceInterceptor(serviceClass, host);
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(serviceClass);
        enhancer.setCallback(interceptor);
        return (T) enhancer.create();
    }
}
public class ServiceInterceptor implements MethodInterceptor {

    public static final MediaType JSON_TYPE = MediaType.get("application/json; charset=utf-8");

    private Class serviceClass;

    private String host;

    public ServiceInterceptor(Class serviceClass, String host) {
        this.serviceClass = serviceClass;
        this.host = host;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String serviceClassName = serviceClass.getName();
        String methodName = method.getName();
        RpcRequest rpcRequest = RpcRequest.builder().serviceClass(serviceClassName).methodName(methodName)
                .params(objects).build();
        String reqJson = JSON.toJSONString(rpcRequest);
        OkHttpClient client = new OkHttpClient();
        final Request request = new Request.Builder()
                .url(host)
                .post(RequestBody.create(JSON_TYPE, reqJson))
                .build();
        String respJson = Objects.requireNonNull(client.newCall(request).execute().body()).string();
        RpcResponse rpcResponse = JSON.parseObject(respJson, RpcResponse.class);
        if (!rpcResponse.isSuccess()) {
            throw rpcResponse.getException();
        }
        return JSON.parse(rpcResponse.getData().toString());
    }
}

2.本地序列化、反序列化

使用Json序列化

  • 使用fastjson
RpcRequest rpcRequest = RpcRequest.builder().serviceClass(serviceClassName).methodName(methodName)
                .params(objects).build();
String reqJson = JSON.toJSONString(rpcRequest);
...
RpcResponse rpcResponse = JSON.parseObject(respJson, RpcResponse.class);

3.网络通信

使用http协议

  • 使用了okhttp
OkHttpClient client = new OkHttpClient();
        final Request request = new Request.Builder()
                .url(host)
                .post(RequestBody.create(JSON_TYPE, reqJson))
                .build();
        String respJson = Objects.requireNonNull(client.newCall(request).execute().body()).string();

4.远程序列化、反序列化

同样使用Json序列化

  • 利用spring框架直接使用对象操作
 @PostMapping("/")
    public RpcResponse invoke(@RequestBody RpcRequest request) {
        return invoker.invoke(request);
    }

5. 远程服务存根

利用spring的beanFactory找到Service实现

  • 实现ApplicationContextAware接口
@Setter
public class ServiceInvoker implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public RpcResponse invoke(RpcRequest rpcRequest) {
        try {
            Class<?> serviceClass = Class.forName(rpcRequest.getServiceClass());
            Method method = Arrays.stream(serviceClass.getMethods()).filter(m -> m.getName()
                    .equals(rpcRequest.getMethodName())).findFirst().get();
            final Object service = applicationContext.getBean(serviceClass);
            Object data = method.invoke(service, rpcRequest.getParams());
            return RpcResponse.builder().data(JSON.toJSONString(data, SerializerFeature.WriteClassName)).success(true).build();
        } catch (Exception e) {
            return RpcResponse.builder().exception(e).success(true).build();
        }
    }
}

6. 调用实际业务服务

通过反射调用

  • 根据参数中的serviceName,methodName反射得到对应的class和method对象
Class<?> serviceClass = Class.forName(rpcRequest.getServiceClass());
Method method = Arrays.stream(serviceClass.getMethods()).filter(m -> m.getName()
                    .equals(rpcRequest.getMethodName())).findFirst().get();
final Object service = applicationContext.getBean(serviceClass);
Object data = method.invoke(service, rpcRequest.getParams());

7. 原路返回服务结果

  • 重要:序列化后要包含类的信息,让调用端可以正确反序列化
RpcResponse.builder().data(JSON.toJSONString(data, SerializerFeature.WriteClassName)).success(true).build();

8. 返回给本地调用方

思考

上述仅仅实现了rpc的基本功能,在此之上,还可以实现一些扩展功能,比如负载均衡、路由、容错等功能。对于基本功能,也有很多可以优化的地方,比如服务注册发现,网络通信优化等等。

代码

https://gitee.com/morehard/demo/tree/master/simple-rpc

相关文章

  • RPC框架的最简单实现

    一个最简单的RPC框架实现包含暴露服务、引用服务、Socket通讯三部分。 RPC框架简易实现 接口 接口实现 服...

  • RPC框架的最简单实现

    一个最简单的RPC框架实现包含暴露服务、引用服务、Socket通讯三部分。 RPC框架简易实现 public cl...

  • 实现简单的RPC框架

    仅实现最基本的功能 RPC原理 实现步骤 1. 本地代理存根 使用cglib获取代理Service 在本地获取Se...

  • Netty高级篇

    本文将用netty实现一个简单的RPC框架。 一、什么叫RPC? RPC,远程调用,就是A程序部署在1号机器上,B...

  • grpc原理

    RPC 框架原理 RPC 框架的目标就是让远程服务调用更加简单、透明,RPC 框架负责屏蔽底层的传输方式(TCP ...

  • Java实现简单的RPC框架

    一、RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议。...

  • Java实现简单的RPC框架

    1 RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议。...

  • Java实现简单的RPC框架

    动态代理例子 使用动态代理的步骤很简单, 可以概括为如下两步: 实现 InvocationHandler 接口, ...

  • 手写类似dubbo的rpc框架第一章《自定义配置xml》

    案例介绍本案例通过三个章节来实现一共简单的rpc框架,用于深入学习rpc框架是如何通信的,当前章节主要介绍如何自定...

  • 基于Netty+动态代理+反射 实现简单的RPC调用

    前言 本文只是简单实现了一次RPC调用示例,以理解其调用原理。一些主流RPC框架的其他功能并没有实现。(如服务自动...

网友评论

      本文标题:实现简单的RPC框架

      本文链接:https://www.haomeiwen.com/subject/cfldyltx.html