前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >项目推荐 I 手写RPC框架(一)

项目推荐 I 手写RPC框架(一)

作者头像
用户3946442
发布2022-04-11 18:38:14
1.1K0
发布2022-04-11 18:38:14
举报
文章被收录于专栏:程序媛驿站

在这篇推文中,小媛将为大家推荐一个Java项目——手写RPC框架。

前言

RPC框架代码量较多,将仅对核心过程进行梳理,完整代码见:https://github.com/wdw87/wRpc

在这篇推文中,将对项目本身以及技术栈进行进行简单介绍,并且给出框架测试Demo

在接下来的系统推文中,将对项目进行详细的介绍

主要将按照下面的内容进行分配:

手写RPC框架(一)

RPC简介、技术栈介绍、测试Demo

手写RPC框架(二)

远程通信实现

手写RPC框架(三)

制定协议与编解码器、动态代理

手写RPC框架(四)

注册中心

一、什么是RPC

RPC(Remote Procedure Call)即远程过程调用,是一种计算的通讯框架。该框架允许运行与一台计算机上的程序调用另一台计算机的程序,而程序员无需为这个交互过程做额外的编程。

RPC框架有很多,例如阿里的Dubbo,谷歌的gRPC等

一个简单的RPC框架主要涉及如下内容

  • 动态代理
  • 反射
  • 序列化和反序列化
  • 编码与解码
  • 网络通信
  • 服务注册与服务发现
  • ...

完整代码见:https://github.com/wdw87/wRpc

二、技术栈

  • Spring框架,项目的基础框架,方便打包,调试,并且基于Spring实现框架配置
  • Netty,使用基于Netty的异步IO,提高网络通信性能
  • zookeeper,基于zookeeper实现服务注册与服务发现
  • fastjson,实现序列化和反序列化
  • cglib,实现动态代理

三、Demo

框架介绍完毕,接下来测试一下框架:

在框架注册两个服务:

  • calculate:实现加法减法运算
  • multiply:实现乘法运算

完整代码见:https://github.com/wdw87/wRpc

1. 服务端

配置
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:wrpc="https://www.wdw87.com/schema/wrpc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       https://www.wdw87.com/schema/wrpc
       https://www.wdw87.com/schema/wrpc/wrpc.xsd
">
    <wrpc:application name="rpc_provider"/>
    <!--服务器提供服务的端口-->
    <wrpc:server port="8000" />
    <!--注册中心-->
    <wrpc:registry registry_address="123.57.175.207:2181" connection_timeout="20000" session_timeout="20000"/>
    <!--服务一-->
    <wrpc:service id="calculate" name="com.wdw.wrpc.service.CalculateInterFace" ref="CalculateInterFaceImpl"/>
    <bean name="CalculateInterFaceImpl" class="com.wdw.wrpc.service.impl.CalculateImpl"/>
    <!--服务二-->
    <wrpc:service id = "multiply" name="com.wdw.wrpc.service.MultiplyInterface" ref="MultiplyImpl"/>
    <bean name="MultiplyImpl" class="com.wdw.wrpc.service.impl.MultiplyImpl"/>
</beans>
服务类
代码语言:javascript
复制
/**
* 服务一
*/
public interface CalculateInterFace {
    int add(int a, int b);
    int dec(int a, int b);
}
public class CalculateImpl implements CalculateInterFace {
    @Override
    public int add(int a, int b) {
        return a + b;
    }

    @Override
    public int dec(int a, int b) {
        return a - b;
    }
}
/**
* 服务二
*/
public interface MultiplyInterface {
    Double multiply(Double a, Double b);
}
public class MultiplyImpl implements MultiplyInterface {
    @Override
    public Double multiply(Double a, Double b) {
        return a * b;
    }
}
服务端编程
代码语言:javascript
复制
public class Server {
    public static void main(String[] args) throws InterruptedException {
        //Spring框架读取配置文件,启动
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
        context.start();
    }
}

2. 客户端

配置
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:wrpc="https://www.wdw87.com/schema/wrpc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       https://www.wdw87.com/schema/wrpc
       https://www.wdw87.com/schema/wrpc/wrpc.xsd
">
    <wrpc:application name="rpc_consumer"/>
    <!--负载均衡策略和动态代理方式-->
    <wrpc:client load_balance="random" proxy="cglib"/>
    <!--注册中心-->
    <wrpc:registry registry_address="123.57.175.207:2181" connection_timeout="20000" session_timeout="20000"/>
    <!--引用服务一-->
    <wrpc:reference id="calculate" name="com.wdw.wrpc.service.CalculateInterFace"/>
    <!--引用服务一-->
    <wrpc:reference id="multiply" name="com.wdw.wrpc.service.MultiplyInterface"/>
</beans>
服务接口

接口与服务端相互统一

代码语言:javascript
复制
/**
* 服务一
*/
public interface CalculateInterFace {
    int add(int a, int b);
    int dec(int a, int b);
}
/**
* 服务二
*/
public interface MultiplyInterface {
    Double multiply(Double a, Double b);
}
客户端编程
代码语言:javascript
复制
public class Client {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
        applicationContext.start();
        //调用服务一
        CalculateInterFace bean = (CalculateInterFace)SpringUtil.getApplicationContext().getBean("calculate");
        System.out.println(bean.add(1,2));
        System.out.println(bean.dec(10,2));
        //调用服务二
        MultiplyInterface bean1 = (MultiplyInterface)SpringUtil.getApplicationContext().getBean("multiply");
        System.out.println(bean1.multiply(3.5,5.5));
    }
}

3. 启动测试

服务端

服务端启动后,首先启动了Netty服务器,然后连接了Zookeeper,并将两个服务注册到Zookeeper,日志如下:

代码语言:javascript
复制
...
[2020-03-29 17:55:48 下午]:INFO com.wdw.wrpc.server.netty.NettyServer.start(NettyServer.java:46)服务端启动中...
[2020-03-29 17:55:48 下午]:INFO com.wdw.wrpc.server.netty.NettyServer$2.operationComplete(NettyServer.java:70)server boot successful, bind port [8000]
[2020-03-29 17:55:49 下午]:INFO com.wdw.wrpc.server.registry.ServiceRegistry.connectServer(ServiceRegistry.java:51)zookeeper 已连接
[2020-03-29 17:55:50 下午]:INFO com.wdw.wrpc.server.registry.ServiceRegistry.register(ServiceRegistry.java:73)注册了服务:/wrpc/com.wdw.wrpc.service.CalculateInterFace/providers/192.168.1.46:8000
[2020-03-29 17:55:50 下午]:INFO com.wdw.wrpc.server.registry.ServiceRegistry.register(ServiceRegistry.java:73)注册了服务:/wrpc/com.wdw.wrpc.service.MultiplyInterface/providers/192.168.1.46:8000
    ...
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.server.netty.ServiceRequestHandler.channelActive(ServiceRequestHandler.java:30)客户端建立了连接
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.server.netty.ServiceRequestHandler.channelRead0(ServiceRequestHandler.java:64)Service invoked : ServiceRequestPacket{id='0082455e56de40e69dce96a43ded890d', className='com.wdw.wrpc.service.CalculateInterFace', methodName='add', parameterTypes=[int, int], args=[1, 2]}
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.server.netty.ServiceRequestHandler.channelRead0(ServiceRequestHandler.java:64)Service invoked : ServiceRequestPacket{id='da862a30b3bf4e7f93f1ee2776cb5444', className='com.wdw.wrpc.service.CalculateInterFace', methodName='dec', parameterTypes=[int, int], args=[10, 2]}
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.server.netty.ServiceRequestHandler.channelActive(ServiceRequestHandler.java:30)客户端建立了连接
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.server.netty.ServiceRequestHandler.channelRead0(ServiceRequestHandler.java:64)Service invoked : ServiceRequestPacket{id='5b0eac41b43a430f9df91846f2e696a5', className='com.wdw.wrpc.service.MultiplyInterface', methodName='multiply', parameterTypes=[class java.lang.Double, class java.lang.Double], args=[3.5, 5.5]}
...

然后,客户端发起调用请求时,服务端调用了相应服务的实现类,并且相应调用结果

客户端

客户端启动后,日志如下:

针对两个服务,经历了如下过程:

  • 连接Zookeeper
  • 发布客户端引用
  • 获取服务列表
  • 监听服务变化
代码语言:javascript
复制
[2020-03-29 17:55:55 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.connectServer(ServiceDiscovery.java:70)zookeeper 已连接

[2020-03-29 17:55:55 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.registerReference(ServiceDiscovery.java:103)客户端引用发布成功:[/wrpc/com.wdw.wrpc.service.CalculateInterFace/consumers/192.168.1.46]
[2020-03-29 17:55:55 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.getReference(ServiceDiscovery.java:113)正在获取服务引用[com.wdw.wrpc.service.CalculateInterFace]
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.getReference(ServiceDiscovery.java:122)发现服务器列表[192.168.1.46:8000]
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.getReference(ServiceDiscovery.java:124)引用服务获取完成[/wrpc/com.wdw.wrpc.service.CalculateInterFace/providers]:com.wdw.wrpc.service.CalculateInterFace


[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.registerReference(ServiceDiscovery.java:103)客户端引用发布成功:[/wrpc/com.wdw.wrpc.service.MultiplyInterface/consumers/192.168.1.46]
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.getReference(ServiceDiscovery.java:113)正在获取服务引用[com.wdw.wrpc.service.MultiplyInterface]
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.getReference(ServiceDiscovery.java:122)发现服务器列表[192.168.1.46:8000]
[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.client.registry.ServiceDiscovery.getReference(ServiceDiscovery.java:124)引用服务获取完成[/wrpc/com.wdw.wrpc.service.MultiplyInterface/providers]:com.wdw.wrpc.service.MultiplyInterface


[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.client.netty.ServiceResponseHandler.channelActive(ServiceResponseHandler.java:25)Client connected.
3
8

[2020-03-29 17:55:56 下午]:INFO com.wdw.wrpc.client.netty.ServiceResponseHandler.channelActive(ServiceResponseHandler.java:25)Client connected.
19.25

当客户端执行调用时,客户端连接服务器,得到调用结果。

完整代码见:https://github.com/wdw87/wRpc

作者:好吃懒做贪玩东

编辑:西瓜媛

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序媛驿站 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 在这篇推文中,小媛将为大家推荐一个Java项目——手写RPC框架。
  • 前言
  • 一、什么是RPC
  • 二、技术栈
  • 三、Demo
  • 1. 服务端
    • 配置
      • 服务类
        • 服务端编程
          • 2. 客户端
            • 配置
            • 服务接口
            • 客户端编程
          • 3. 启动测试
            • 服务端
            • 客户端
        相关产品与服务
        文件存储
        文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档