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主要是为了解决的两个问题: 解决分布式系统 ...
随机推荐
- 图论--2-SAT--POJ Ikki's Story IV - Panda's Trick
Description liympanda, one of Ikki's friend, likes playing games with Ikki. Today after minesweeping ...
- 图论——Tarjan 初步 DFS序+时间戳+欧拉序
一.什么是DFS序: DFS序是按照先序遍历,先遍历根节点然后依次遍历左子树,右子树的过程,每次遇到新的节点就把新访问节点加到序列中,代码如下: int DFSrk[100000]; int cnt= ...
- python selenium(用例断言)
1.if ...else ...判断进行断言 from time import * from selenium import webdriver "): driver = webdriver ...
- Https双向验证与Springboot整合测试-人来人往我只认你
1 简介 不知不觉Https相关的文章已经写了6篇了,本文将是这个专题的最后一篇,起码近期是最后一篇.前面6篇讲的全都是单向的Https验证,本文将重点介绍一下双向验证.有兴趣的同学可以了解一下之前的 ...
- Android P HIDL demo代码编写 (原创)
之前的文章已经分析了HIDL服务的注册和调用,这篇文章来总结下一个HIDL的服务如何编写. 缩写HAL文件 首先要确认放置文件夹和接口的包名,因为这跟后面使用脚本生成一部分代码有关,一般默认的放在ha ...
- 王颖奇 20171010129《面向对象程序设计(java)》第十六周学习总结
实验十六 线程技术 实验时间 2018-12-8 理论部分: 并发⚫ 线程的概念⚫ 中断线程⚫ 线程状态⚫ 多线程调度⚫ 线程同步 1.线程的概念 程序是一段静态的代码,它是应用程序执行的蓝本. 进 ...
- WPF - 简单的UI框架
实现了一个简单的WPF应用程序UI框架 ,分享出来.界面效果图如下: 运行效果如下: 喜欢的可以下载源码参考:https://github.com/DuelWithSelf/WPFEffects 左侧 ...
- PrintStream:打印流
package com.itheima.demo05.PrintStream; import java.io.FileNotFoundException; import java.io.PrintSt ...
- 聊聊 TypeScript 中的类型保护
聊聊 TypeScript 中的类型保护 在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况: interface Bird { // 独有方法 fly(); // 共有方法 lay ...
- OpenCV开发笔记(五十五):红胖子8分钟带你深入了解Haar、LBP特征以及级联分类器识别过程(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...