Java使用Netty实现简单的RPC
造一个轮子,实现RPC调用
在写了一个Netty实现通信的简单例子后,萌发了自己实现RPC调用的想法,于是就开始进行了Netty-Rpc的工作,实现了一个简单的RPC调用工程。
如果也有兴趣动手造轮子的同学,可以先看看之前写的 使用Java实现Netty通信 这篇博客。
本文源地址:造一个RPC的轮子
准备
首先,你需要明白下列知识。
Netty
处理服务之间的通信。
Zookeeper
服务注册与发现。
SpringBoot
目前单单只是作为启动项目。
Cglib Proxy & Jdk Reflect
使用代理实例化暴露的接口,通过反射调用接口方法的实现。
RPC处理流程

- 服务提供者通过Netty进行对应的端口暴露。
- 同时提供者将需要暴露的服务信息注册到Zookeeper,Zookeeper注册的节点信息为接口的类路径,注册的Data为暴露的端口,并且需要将对应的接口实现类在ApplicationContext上下文中进行保存。
- 此时消费者启动后,会根据对应接口的类路径在Zookeeper进行Discover。
- 根据对应接口的类路径在Zookeeper中通过ReadData获取到对应暴露的端口信息。
- 拿到了端口信息,通过Netty发起请求。
- Netty发起请求接收后,通过之前的ApplicationContext上下文调用对应的接口方法。
- ApplicationContext调用成功后,Netty将响应的结果返回。
- 服务消费者得到响应结果,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的更多相关文章
- netty 实现简单的rpc调用
yls 2020/5/23 netty 实现简单rpc准备 使用netty传输java bean对象,可以使用protobuf,也可以通过json转化 客户端要将调用的接口名称,方法名称,参数列表的类 ...
- Java实现简单的RPC框架(美团面试)
一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...
- 教你用 Netty 实现一个简单的 RPC!
众所周知,dubbo 底层使用了 Netty 作为网络通讯框架,而 Netty 的高性能我们之前也分析过源码,对他也算还是比较了解了. 今天我们就自己用 Netty 实现一个简单的 RPC 框架. 1 ...
- 自己用 Netty 实现一个简单的 RPC
目录: 需求 设计 实现 创建 maven 项目,导入 Netty 4.1.16. 项目目录结构 设计接口 提供者相关实现 消费者相关实现 测试结果 总结 源码地址:github 地址 前言 众所周知 ...
- 分布式架构的基石.简单的 RPC 框架实现(JAVA)
前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...
- 造个轮子之基于 Netty 实现自己的 RPC 框架
原文地址: haifeiWu和他朋友们的博客 博客地址:www.hchstudio.cn 欢迎转载,转载请注明作者及出处,谢谢! 服务端开发都会或多或少的涉及到 RPC 的使用,当然如果止步于会用,对 ...
- java使用netty模拟实现一个类dubbo的分布式服务调用框架
本文较长,如果想直接看代码可以查看项目源码地址: https://github.com/hetutu5238/rpc-demo.git 要想实现分布式服务调用框架,我们需要了解分布式服务一般需要的功能 ...
- 最简单的RPC框架实现
通过java原生的序列化,Socket通信,动态代理和反射机制,实现一个简单的RPC框架,由三部分组成: 1.服务提供者,运行再服务端,负责提供服务接口定义和服务实现类 2.服务发布者,运行再RPC服 ...
- 如何实现一个简单的RPC
在如何给老婆解释什么是RPC中,我们讨论了RPC的实现思路. 那么这一次,就让我们通过代码来实现一个简单的RPC吧! RPC的实现原理 正如上一讲所说,RPC主要是为了解决的两个问题: 解决分布式系统 ...
随机推荐
- 关于RMQ问题的四种解法
什么是RMQ问题: RMQ (Range Minimum/Maximum Query):对于长度为n的数组A,回答若干询问RMQ(A,i,j)(i,j<=n-1),返回数组A中下标在i, ...
- P5522 [yLOI2019] 棠梨煎雪
updata on 2020.3.19 今天把博客从洛谷往博客园搬,图炸了 其实早就发现了,懒得管 那图其实就是一个用dev自带的调试功能调试时,RE了的报错 当时觉得很奇怪看不出是啥,现在再看已经觉 ...
- postman(断言)
一.断言 1.Code is 200 断言状态码是200 2.contains string 断言respoonse body中包含string 3.json value check (检查JSON值 ...
- 惠普 HP Pavilion 15 Notebook PC清灰教程总结 惠普g4系列清灰加内存条教程
最近天气热的电脑都受不了,风扇总是异响,声音很大,感觉是散热不行了,就把电脑清一下灰,虽然之前也清过,但是基本都忘记了,机子比较老,找不到具体教程,清灰过程中因为不熟悉有点费劲,手动记录一下,方便下次 ...
- idea 将项目托管到 Git 报错:Can't finish Gitee sharing process
在idea中报: Can't finish Gitee sharing processSuccssully created project 'dmp' on Gitee. but initial co ...
- 从零搭建分布式文件系统MinIO比FastDFS要更合适
前两天跟大家分享了一篇关于如何利用FastDFS组件来自建分布式文件系统的文章,有兴趣的朋友可以阅读下<用asp.net core结合fastdfs打造分布式文件存储系统>.通过留言发现大 ...
- 程序猿使用Python的tkinter库进行GUI编程肯定要会的事件处理
事件类型用户通过鼠标.键盘.游戏控制设备在与图形界面交互时,就会触发事件.tkinter事件通常采用了将事件名称放置于尖括号内的字符串表示,尖括号中的内容我们称之为事件类型.事件类型有其通用的定义方式 ...
- LeetCode--LinkedList--83.Remove Duplicates from Sorted List(Easy)
题目地址https://leetcode.com/problems/remove-duplicates-from-sorted-list/ 83. Remove Duplicates from Sor ...
- 【Hadoop离线基础总结】HDFS的API操作
HDFS的API操作 创建maven工程并导入jar包 注意 由于cdh版本的所有的软件涉及版权的问题,所以并没有将所有的jar包托管到maven仓库当中去,而是托管在了CDH自己的服务器上面,所以我 ...
- 如何使用apt-get在ubuntu系统上安装OpenJDK 8
文章目录 添加ppa仓库 设置openjdk版本 查看java 版本 Android 8.1 系统编译的时候需要安装OpenJDK 8,这里如果可以自己下载源码编译安装,当然本想编译Android系统 ...