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主要是为了解决的两个问题: 解决分布式系统 ...
随机推荐
- libevent(一)定时器Demo
开始研究libevent,使用的版本是2.0.22. 实现一个定时器:每2秒执行一次printf. #include <stdio.h> #include <stdlib.h> ...
- ASP.NET Core 如何使用Mvc相关技术建立Controller、Tag Helper (下)
上篇文章介绍了通过定义两个接口和服务类,分别实现这两个接口,并且进行了一个服务的注册. 今天就来建立Controller 接下来就是在控制器中通过构造函数的方式注入接口(见代码块6行) 代码块2行的意 ...
- I - Union 2019ccpc女生赛
I - Union 这是2019女生赛最难的一个题目,但是现在去写,我觉得没有想象之中的那么难. 把这个题目分成几个部分来考虑. 假设给你k个数,让你分成三个集合,满足这四个条件,且不需要考虑时间和空 ...
- 一文教你快速搞懂速度曲线规划之S形曲线(超详细+图文+推导+附件代码)
本文介绍了运动控制终的S曲线,通过matlab和C语言实现并进行仿真:本文篇幅较长,请自备茶水: 请帮忙点个赞
- 设计模式GOF23大纲
创建型模式: 单例模式,工厂模式,抽象工厂模式 结构型模式: 适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式 行为型模式: 模板方法模式,命令模式,迭代器模式,观察者模式,中介 ...
- [hdu5351]找规律,大整数模板
题意:f(1)="a",f(2)="b",f(i)=f(i-1)+f(i-2),"+"表示连接符.给定n,m,求f(n)的前m个字符的“ne ...
- Mysql 常用函数(9)- reverse 函数
Mysql常用函数的汇总,可看下面系列文章 https://www.cnblogs.com/poloyy/category/1765164.html reverse 的作用 将字符串反转,即顺序取反 ...
- jsp 中文乱码????解决
中文乱码是个非常蛋疼的问题,在页面表单提交的时候后台获取数据变成了????,解决方案如下: 1:确认编码都是一致的如页面和后台都设置为utf-8 2:String str = new String(r ...
- 【Effective Java】第二章-创建和销毁对象——1.考虑用静态工厂方法代替构造器
静态工厂方法的优点: 可以赋予一个具有明确含义的名称 可以复用唯一实例,不必每次新建 可以返回原实例类型的子类对象 可以在返回泛型实例时更加简洁 缺点: 类如果不含有共有的或者受保护的构造器,就不能被 ...
- fastadmin后台:选择视频并允许上传到服务器
1.在对应方法的视图 “view/class/add.html" 中上传视频部分添加:data-mimetype="video/mp4" 2.在 ”applicatio ...