• 「造轮子」一个简单的 RPC 框架(基于Netty+Zookeeper+Spring)


    概述

    RPC框架只提供了基本功能,即远程调用,大家可以在此基础上添加负载均衡,异步调用等功能。
    项目地址:https://github.com/hczs/simple-rpc

    所用技术栈

    1. 首先我们需要发网络请求进行调用,这里使用网络框架 Netty
    2. 然后调用之间的消息需要序列化和反序列化,这里使用序列化框架 protostuff
    3. 再然后呢我们需要知道服务提供方地址是多少,也就是 服务发现/ 服务注册,我们使用 Zookeeper 来管理服务,使用 Curator 框架来操作 Zookeeper
    4. 我们使用 Spring 来方便的管理 Bean 进行随意的注入使用,以及配置文件值注入
    5. 使用 lombok 来精简代码,方便快速开发
    6. 使用 objenesis 库来优化我们反序列化 请求 / 响应对象的速度
    7. 使用 cglib 来优化我们接收响应处理执行方法的速度
    8. 使用 commons.lang3 库中的一些常用工具类

    整体设计

    整体架构

    使用方法

    注意:需要提前启动 Zookeeper 才能正常运行

    1. 创建 simple-rpc-demo-api 工程,编写接口定义

    package icu.sunnyc.rpc.demo.api;
    
    /**
     * 示例接口
     * @author: houcheng
     * @date: 2022/5/31 16:26:10
     */
    public interface HelloService {
    
        /**
         * 示例方法
         * @param name 字符串参数
         * @return String
         */
        String hello(String name);
    
        /**
         * 返回这个学生一年后的样子
         * @param student 学生对象
         * @return 一年后的学生对象
         */
        Student oneYearLater(Student student);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2. 创建 simple-rpc-demo-producer 工程

    2.1 依赖 api 和 simple-rpc-core (即 simple-rpc 核心代码工程)

    <dependencies>
        <!-- api -->
        <dependency>
            <groupId>icu.sunnyc</groupId>
            <artifactId>simple-rpc-demo-api</artifactId>
            <version>${project.version}</version>
        </dependency>
    
        <!-- rpc-core -->
        <dependency>
            <groupId>icu.sunnyc</groupId>
            <artifactId>simple-rpc-core</artifactId>
            <version>${project.version}</version>
        </dependency>
    
    </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.2 添加 simple-rpc.properties 配置文件

    在 src/main/resources 下新建 simple-rpc.properties 配置文件,此配置文件名称不能修改,写入以下内容:

    # Zookeeper connection string
    # 注册中心地址
    registry.address=127.0.0.1:2181
    
    # RpcServer port
    # 你的 rpc 服务端启动地址
    service.address=127.0.0.1:13356
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.3 实现 simple-rpc-demo-api 中定义的接口

    package icu.sunnyc.rpc.demo.producer.impl;
    
    import icu.sunnyc.rpc.core.annotation.RpcService;
    import icu.sunnyc.rpc.demo.api.HelloService;
    import icu.sunnyc.rpc.demo.api.Student;
    
    /**
     * HelloService 实现类
     * @author: houcheng
     * @date: 2022/5/31 16:30:43
     */
    @RpcService(HelloService.class)
    public class HelloServiceImpl implements HelloService {
    
        @Override
        public String hello(String name) {
            return "Hello " + name;
        }
    
        @Override
        public Student oneYearLater(Student student) {
            System.out.println("生产者收到学生信息:" + student);
            // 一年后年龄 + 1
            student.setAge(student.getAge() + 1);
            return student;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    2.4 编写生产者(服务提供者)启动类

    package icu.sunnyc.rpc.demo.producer;
    
    import icu.sunnyc.rpc.core.RpcApplication;
    
    /**
     * RPC 服务启动类 启动自动注册服务
     * @author: houcheng
     * @date: 2022/5/31 16:50:03
     */
    public class ProducerApplication {
    
        public static void main(String[] args) {
            RpcApplication.run(ProducerApplication.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3. 创建 simple-rpc-demo-consumer 工程

    3.1 依赖 api 和 simple-rpc-core

    <dependencies>
        <!-- api -->
        <dependency>
            <groupId>icu.sunnyc</groupId>
            <artifactId>simple-rpc-demo-api</artifactId>
            <version>${project.version}</version>
        </dependency>
    
        <!-- rpc-core -->
        <dependency>
            <groupId>icu.sunnyc</groupId>
            <artifactId>simple-rpc-core</artifactId>
            <version>${project.version}</version>
        </dependency>
    
    </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.2 添加 simple-rpc.properties 配置文件

    在 src/main/resources 下新建 simple-rpc.properties 配置文件,此配置文件名称不能修改,写入以下内容:

    # Zookeeper connection string
    # 调用端如果不提供服务的话,只需要配置注册中心地址即可
    registry.address=127.0.0.1:2181
    
    • 1
    • 2
    • 3

    3.3 编写消费者(服务调用者)启动类

    package icu.sunnyc.rpc.demo.consumer;
    
    
    import icu.sunnyc.rpc.core.RpcApplication;
    import icu.sunnyc.rpc.core.annotation.SimpleReference;
    import icu.sunnyc.rpc.demo.api.HelloService;
    import icu.sunnyc.rpc.demo.api.Student;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.stereotype.Component;
    
    import java.util.Random;
    
    /**
     * RPC 调用测试
     * @author: houcheng
     * @date: 2022/6/1 16:43:05
     */
    @Component
    public class ConsumerApplication {
    
        @SimpleReference
        private HelloService helloService;
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = RpcApplication.run(ConsumerApplication.class);
            ConsumerApplication consumerApplication = context.getBean(ConsumerApplication.class);
            
            // 简单参数类型调用
            System.out.println(consumerApplication.sayHello("sunnyc"));
    
            // 复杂参数类型调用
            consumerApplication.callOneYearLater();
        }
    
        public String sayHello(String name) {
            return helloService.hello(name);
        }
    
        public void callOneYearLater() {
            Student student = new Student();
            student.setName("sunnyc");
            student.setAge(18);
            student.setGender("male");
            System.out.println("一年前的学生:" + student);
            System.out.println("一年后的学生:" + helloService.oneYearLater(student));
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    4. 验证

    先启动生产者,再启动消费者进行调用,不出意外消费者控制台会出现以下内容:

    ...省略若干日志
    Hello sunnyc
    一年前的学生:Student{name='sunnyc', age=18, gender='male'}
    ...省略调用过程的日志
    一年后的学生:Student{name='sunnyc', age=19, gender='male'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    Dataset之GermanCreditData:GermanCreditData数据集的简介、下载、使用方法之详细攻略
    蓝桥杯 题库 简单 每日十题 day7
    还不懂Java线程池实现原理,看这一篇文章就够了
    Java并发编程--变量可见性、避免指令重排,还得是用它
    算法9-动态规划
    linux uboot kenerl filesystem关系
    容易忽视的细节:Log4j 配置导致的零点接口严重超时
    linux常用命令收集
    PCL点云处理(008)-euc_cluster
    超透镜与超表面全息
  • 原文地址:https://blog.csdn.net/hsunnyc/article/details/125459489