造一个轮子,实现RPC调用

在写了一个Netty实现通信的简单例子后,萌发了自己实现RPC调用的想法,于是就开始进行了Netty-Rpc的工作,实现了一个简单的RPC调用工程。



如果也有兴趣动手造轮子的同学,可以先看看之前写的 使用Java实现Netty通信 这篇博客。



本文源地址:造一个RPC的轮子


准备

首先,你需要明白下列知识。

Netty

处理服务之间的通信。

Zookeeper

服务注册与发现。

SpringBoot

目前单单只是作为启动项目。

Cglib Proxy & Jdk Reflect

使用代理实例化暴露的接口,通过反射调用接口方法的实现。


RPC处理流程

  1. 服务提供者通过Netty进行对应的端口暴露。
  2. 同时提供者将需要暴露的服务信息注册到Zookeeper,Zookeeper注册的节点信息为接口的类路径,注册的Data为暴露的端口,并且需要将对应的接口实现类在ApplicationContext上下文中进行保存。
  3. 此时消费者启动后,会根据对应接口的类路径在Zookeeper进行Discover。
  4. 根据对应接口的类路径在Zookeeper中通过ReadData获取到对应暴露的端口信息。
  5. 拿到了端口信息,通过Netty发起请求。
  6. Netty发起请求接收后,通过之前的ApplicationContext上下文调用对应的接口方法。
  7. ApplicationContext调用成功后,Netty将响应的结果返回。
  8. 服务消费者得到响应结果,RPC流程结束。

动手

使用Java实现Netty通信 这篇文章的基础上,我们新建下列工程信息。

rpc-sample-api

依赖信息

<dependency>
<groupId>com.yanzhenyidai</groupId>
<artifactId>netty-rpc-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

代码

只需要定义一个HiService接口。

public interface HiService {

    public String hi(String msg);
}

rpc-sample-server

依赖信息

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.3.RELEASE</version>
</dependency> <dependency>
<groupId>com.yanzhenyidai</groupId>
<artifactId>rpc-sample-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency> <dependency>
<groupId>com.yanzhenyidai</groupId>
<artifactId>netty-rpc-server</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

application.yaml

register.address: 127.0.0.1:3000

代码

  • 首先实现HiService接口。
@RpcServer(cls = HiService.class)
public class HiServiceImpl implements HiService { public String hi(String msg) {
return "hello, I'm Rpc, I want say : " + msg;
}
}
  • Server类。
@Component
public class Server implements ApplicationContextAware { private static final Logger logger = LoggerFactory.getLogger(Server.class); @Value("${register.address}")
private String registerAddress; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, Object> serviceBean = new HashMap<String, Object>(); Map<String, Object> objectMap = applicationContext.getBeansWithAnnotation(RpcServer.class); for (Object object : objectMap.values()) {
try {
RpcServer annotation = object.getClass().getAnnotation(RpcServer.class); serviceBean.put("/yanzhenyidai/" + annotation.cls().getName(), object); String[] split = registerAddress.split(":"); new NettyServer(split[0], Integer.valueOf(split[1])).server(serviceBean);
} catch (Exception e) {
logger.error("[server-start] fail ", e);
}
}
}
}

实现 ApplicationContextAware 以获取到Spring上下文,通过扫描RpcServer注解,得到本次需要暴露的服务信息,并且开启NettyServer的端口服务暴露及Zookeeper注册。

  • Application启动类
@SpringBootApplication
public class RpcServerApplication { public static void main(String[] args) {
new SpringApplicationBuilder(RpcServerApplication.class)
.web(WebApplicationType.NONE)
.run(args);
}
}

开启SpringBoot无Web启动。

rpc-sample-client

依赖

<dependency>
<groupId>com.yanzhenyidai</groupId>
<artifactId>netty-rpc-client</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency> <dependency>
<groupId>com.yanzhenyidai</groupId>
<artifactId>rpc-sample-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency> <dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.2</version>
</dependency> <dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>

代码

  • Client
public class Client {

    public <T> T create(final Class<?> cls) {

        return (T) Proxy.newProxyInstance(cls.getClassLoader(), new Class<?>[]{cls}, new InvocationHandler() {
public Object invoke(Object o, Method method, Object[] objects) throws Throwable { Request request = new Request();
request.setInterfaceName("/yanzhenyidai/" + cls.getName());
request.setRequestId(UUID.randomUUID().toString());
request.setParameter(objects);
request.setMethodName(method.getName());
request.setParameterTypes(method.getParameterTypes()); Response response = new NettyClient().client(request);
return response.getResult();
}
});
}
}

使用Cglib动态代理先实例化接口信息,在调用的时候,通过NettyClient发送请求到NettyServer,由NettyServer处理发现Zookeeper节点以及反射调用接口实现方法。

  • context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.yanzhenyidai.config.Client"></bean> </beans>

注入Client的bean对象信息。

  • Application
public class RpcClientApplication {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");

        Client client = context.getBean(Client.class);

        HiService hiService = client.create(HiService.class);
String msg = hiService.hi("msg");
System.out.println(msg); }
}

运行结果


总结

以上只是一个简单的RPC过程,相对于Dubbo RPC会更加直观的看明白,希望能对大家有所帮助作用,也欢迎大家和我一起造轮子。

本项目Github地址:Netty-RPC

Java使用Netty实现简单的RPC的更多相关文章

  1. netty 实现简单的rpc调用

    yls 2020/5/23 netty 实现简单rpc准备 使用netty传输java bean对象,可以使用protobuf,也可以通过json转化 客户端要将调用的接口名称,方法名称,参数列表的类 ...

  2. Java实现简单的RPC框架(美团面试)

    一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...

  3. 教你用 Netty 实现一个简单的 RPC!

    众所周知,dubbo 底层使用了 Netty 作为网络通讯框架,而 Netty 的高性能我们之前也分析过源码,对他也算还是比较了解了. 今天我们就自己用 Netty 实现一个简单的 RPC 框架. 1 ...

  4. 自己用 Netty 实现一个简单的 RPC

    目录: 需求 设计 实现 创建 maven 项目,导入 Netty 4.1.16. 项目目录结构 设计接口 提供者相关实现 消费者相关实现 测试结果 总结 源码地址:github 地址 前言 众所周知 ...

  5. 分布式架构的基石.简单的 RPC 框架实现(JAVA)

    前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...

  6. 造个轮子之基于 Netty 实现自己的 RPC 框架

    原文地址: haifeiWu和他朋友们的博客 博客地址:www.hchstudio.cn 欢迎转载,转载请注明作者及出处,谢谢! 服务端开发都会或多或少的涉及到 RPC 的使用,当然如果止步于会用,对 ...

  7. java使用netty模拟实现一个类dubbo的分布式服务调用框架

    本文较长,如果想直接看代码可以查看项目源码地址: https://github.com/hetutu5238/rpc-demo.git 要想实现分布式服务调用框架,我们需要了解分布式服务一般需要的功能 ...

  8. 最简单的RPC框架实现

    通过java原生的序列化,Socket通信,动态代理和反射机制,实现一个简单的RPC框架,由三部分组成: 1.服务提供者,运行再服务端,负责提供服务接口定义和服务实现类 2.服务发布者,运行再RPC服 ...

  9. 如何实现一个简单的RPC

    在如何给老婆解释什么是RPC中,我们讨论了RPC的实现思路. 那么这一次,就让我们通过代码来实现一个简单的RPC吧! RPC的实现原理 正如上一讲所说,RPC主要是为了解决的两个问题: 解决分布式系统 ...

随机推荐

  1. libevent(一)定时器Demo

    开始研究libevent,使用的版本是2.0.22. 实现一个定时器:每2秒执行一次printf. #include <stdio.h> #include <stdlib.h> ...

  2. ASP.NET Core 如何使用Mvc相关技术建立Controller、Tag Helper (下)

    上篇文章介绍了通过定义两个接口和服务类,分别实现这两个接口,并且进行了一个服务的注册. 今天就来建立Controller 接下来就是在控制器中通过构造函数的方式注入接口(见代码块6行) 代码块2行的意 ...

  3. I - Union 2019ccpc女生赛

    I - Union 这是2019女生赛最难的一个题目,但是现在去写,我觉得没有想象之中的那么难. 把这个题目分成几个部分来考虑. 假设给你k个数,让你分成三个集合,满足这四个条件,且不需要考虑时间和空 ...

  4. 一文教你快速搞懂速度曲线规划之S形曲线(超详细+图文+推导+附件代码)

    本文介绍了运动控制终的S曲线,通过matlab和C语言实现并进行仿真:本文篇幅较长,请自备茶水: 请帮忙点个赞

  5. 设计模式GOF23大纲

    创建型模式: 单例模式,工厂模式,抽象工厂模式 结构型模式: 适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式 行为型模式: 模板方法模式,命令模式,迭代器模式,观察者模式,中介 ...

  6. [hdu5351]找规律,大整数模板

    题意:f(1)="a",f(2)="b",f(i)=f(i-1)+f(i-2),"+"表示连接符.给定n,m,求f(n)的前m个字符的“ne ...

  7. Mysql 常用函数(9)- reverse 函数

    Mysql常用函数的汇总,可看下面系列文章 https://www.cnblogs.com/poloyy/category/1765164.html reverse 的作用 将字符串反转,即顺序取反 ...

  8. jsp 中文乱码????解决

    中文乱码是个非常蛋疼的问题,在页面表单提交的时候后台获取数据变成了????,解决方案如下: 1:确认编码都是一致的如页面和后台都设置为utf-8 2:String str = new String(r ...

  9. 【Effective Java】第二章-创建和销毁对象——1.考虑用静态工厂方法代替构造器

    静态工厂方法的优点: 可以赋予一个具有明确含义的名称 可以复用唯一实例,不必每次新建 可以返回原实例类型的子类对象 可以在返回泛型实例时更加简洁 缺点: 类如果不含有共有的或者受保护的构造器,就不能被 ...

  10. fastadmin后台:选择视频并允许上传到服务器

    1.在对应方法的视图  “view/class/add.html" 中上传视频部分添加:data-mimetype="video/mp4" 2.在 ”applicatio ...