🎯 项目简介
guide-rpc-framework 是一个基于 Netty + Kryo + Zookeeper 实现的轻量级 RPC 框架。该项目代码结构清晰,注释详细,非常适合学习 RPC 框架的底层原理和 Java 编程实践。
什么是 RPC? RPC(Remote Procedure Call,远程过程调用)是一种计算机通信协议,允许程序调用另一个地址空间(通常是远程服务器)的过程或函数,就像调用本地函数一样简单。
🏗️ 项目架构总览
guide-rpc-framework/
├── rpc-framework-common/ # 公共模块:工具类、枚举、异常等
├── rpc-framework-simple/ # 核心模块:RPC框架的主要实现
├── hello-service-api/ # API定义模块:接口和数据传输对象
├── example-server/ # 服务端示例:演示如何提供RPC服务
├── example-client/ # 客户端示例:演示如何调用RPC服务
└── config/ # 配置文件:CheckStyle等代码规范配置
📦 模块详细解析
1. hello-service-api 模块 - API 定义层
作用: 定义服务接口和数据传输对象,是客户端和服务端的契约。
核心文件:
HelloService.java - 服务接口
public interface HelloService {
String hello(Hello hello);
}
Hello.java - 数据传输对象
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
@ToString
public class Hello implements Serializable {
private String message;
private String description;
}
为什么需要这个模块?
- 🔗 解耦合:客户端和服务端只需要依赖接口,不需要依赖具体实现
- 📋 契约定义:明确定义了服务的输入输出格式
- 🔄 版本管理:便于接口版本的管理和升级
2. rpc-framework-common 模块 - 公共基础设施
作用: 提供框架运行所需的基础设施,包括工具类、枚举、异常处理等。
主要包结构:
enums/- 枚举类:错误码、响应状态等utils/- 工具类:常用的辅助方法factory/- 工厂类:对象创建和管理exception/- 异常类:自定义异常处理extension/- 扩展机制:SPI 相关实现
核心功能:
- 🛠️ 工具支持:提供字符串、集合等常用工具方法
- 🏭 对象管理:通过工厂模式管理对象的创建
- ⚠️ 异常处理:统一的异常定义和处理机制
- 🔌 扩展机制:支持 SPI 机制,便于功能扩展
3. rpc-framework-simple 模块 - 核心实现层
这是整个框架的核心模块,实现了 RPC 框架的所有主要功能。
3.1 remoting 包 - 网络通信层
作用: 处理客户端和服务端之间的网络通信。
dto 子包 - 数据传输对象
- RpcRequest.java - RPC 请求对象
public class RpcRequest implements Serializable {
private String requestId; // 请求唯一标识
private String interfaceName; // 接口名称
private String methodName; // 方法名称
private Object[] parameters; // 方法参数
private Class<?>[] paramTypes; // 参数类型
private String version; // 服务版本
private String group; // 服务分组
}
- RpcResponse.java - RPC 响应对象
public class RpcResponse<T> implements Serializable {
private String requestId; // 对应的请求ID
private Integer code; // 响应状态码
private String message; // 响应消息
private T data; // 响应数据
}
- RpcMessage.java - 网络传输消息包装器
transport 子包 - 传输层实现
设计模式: 策略模式 + 模板方法模式
- RpcRequestTransport.java - 传输层接口
- socket/ - 基于传统 Socket 的实现
- netty/ - 基于 Netty 的高性能实现
Netty 实现优势:
- 🚀 高性能:基于 NIO,支持高并发
- 💓 心跳机制:保持长连接,避免频繁建连
- 🔄 连接复用:避免重复创建连接
- 📦 协议定制:支持自定义通信协议
3.2 proxy 包 - 动态代理层
作用: 通过动态代理让远程调用像本地调用一样简单。
RpcClientProxy.java - 核心代理类
@Slf4j
public class RpcClientProxy implements InvocationHandler {
private final RpcRequestTransport rpcRequestTransport;
private final RpcServiceConfig rpcServiceConfig;
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// 1. 构建 RPC 请求
// 2. 发送请求到服务端
// 3. 获取响应结果
// 4. 返回结果给调用方
}
}
工作原理:
- 🎭 代理创建:为接口创建代理对象
- 📦 请求封装:将方法调用封装成 RpcRequest
- 🌐 网络传输:通过网络发送请求到服务端
- 📥 结果处理:接收响应并返回给调用方
3.3 registry 包 - 服务注册发现
作用: 实现服务的注册与发现,支持分布式部署。
核心接口:
- ServiceRegistry.java - 服务注册接口
- ServiceDiscovery.java - 服务发现接口
Zookeeper 实现:
- ZkServiceRegistryImpl.java - 基于 ZK 的服务注册
- ZkServiceDiscoveryImpl.java - 基于 ZK 的服务发现
服务注册流程:
- 🏷️ 服务启动:服务提供者启动时注册服务信息
- 📍 路径创建:在 ZK 中创建服务路径节点
- 💾 信息存储:存储服务的 IP、端口等信息
- 👁️ 健康检查:通过临时节点实现服务健康检查
服务发现流程:
- 🔍 查询服务:客户端根据服务名查询可用实例
- 📋 获取列表:从 ZK 获取服务实例列表
- ⚖️ 负载均衡:根据负载均衡算法选择实例
- 🔄 缓存更新:缓存服务列表并监听变化
3.4 serialize 包 - 序列化层
作用: 将 Java 对象转换为字节流进行网络传输。
支持的序列化方式:
- Kryo - 高性能序列化框架(推荐)
- Hessian - 跨语言序列化协议
- Protostuff - 基于 Protobuf 的序列化
Kryo 优势:
- ⚡ 性能优异:序列化速度快,体积小
- 🔧 易于使用:API 简单,集成方便
- 🛡️ 安全可靠:避免了 JDK 序列化的安全问题
3.5 loadbalance 包 - 负载均衡
作用: 在多个服务实例中选择一个进行调用。
实现的算法:
- RandomLoadBalance - 随机选择算法
- ConsistentHashLoadBalance - 一致性哈希算法
一致性哈希优势:
- 📊 数据倾斜少:分布相对均匀
- 🔄 扩展性好:节点增减影响小
- 💾 缓存友好:相同请求总是路由到同一节点
3.6 provider 包 - 服务提供者管理
作用: 管理本地服务实例,处理服务调用请求。
ServiceProvider.java - 服务提供者接口
- 📝 服务注册:注册本地服务实例
- 🔍 服务查找:根据服务名查找服务实例
- 📋 服务管理:管理所有已注册的服务
3.7 annotation 包 - 注解支持
作用: 提供注解方式的服务声明和注入。
核心注解:
- @RpcService - 标记服务实现类
@RpcService(group = "test1", version = "version1")
public class HelloServiceImpl implements HelloService {
// 服务实现
}
- @RpcReference - 注入远程服务
@Component
public class HelloController {
@RpcReference(version = "version1", group = "test1")
private HelloService helloService;
}
- @RpcScan - 扫描服务注解
@RpcScan(basePackage = {"github.javaguide.serviceimpl"})
public class NettyServerMain {
// 应用启动类
}
3.8 spring 包 - Spring 集成
作用: 与 Spring 框架集成,支持自动服务注册和注入。
核心类:
- SpringBeanPostProcessor - Bean 后置处理器
- CustomScanner - 自定义扫描器
- CustomScannerRegistrar - 扫描器注册器
集成原理:
- 🔍 自动扫描:扫描带有 @RpcService 注解的类
- 📝 自动注册:将服务自动注册到注册中心
- 💉 自动注入:为带有 @RpcReference 注解的字段注入代理对象
4. example-server 模块 - 服务端示例
作用: 演示如何使用框架提供 RPC 服务。
核心文件:
HelloServiceImpl.java - 服务实现
@Slf4j
@RpcService(group = "test1", version = "version1")
public class HelloServiceImpl implements HelloService {
@Override
public String hello(Hello hello) {
log.info("HelloServiceImpl收到: {}.", hello.getMessage());
String result = "Hello description is " + hello.getDescription();
log.info("HelloServiceImpl返回: {}.", result);
return result;
}
}
服务启动示例:
- 🔧 注解方式:通过 @RpcScan 自动扫描和注册服务
- 🖐️ 手动方式:通过 API 手动注册服务
5. example-client 模块 - 客户端示例
作用: 演示如何使用框架调用远程 RPC 服务。
调用方式:
注解方式:
@Component
public class HelloController {
@RpcReference(version = "version1", group = "test1")
private HelloService helloService;
public void test() {
String result = helloService.hello(new Hello("111", "222"));
System.out.println(result);
}
}
编程方式:
ClientTransport rpcRequestTransport = new SocketRpcClient();
RpcServiceConfig rpcServiceConfig = RpcServiceConfig.builder()
.group("test2").version("version2").build();
RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcRequestTransport, rpcServiceConfig);
HelloService helloService = rpcClientProxy.getProxy(HelloService.class);
String hello = helloService.hello(new Hello("111", "222"));
🔧 核心技术栈
网络通信
- Netty 4.x - 高性能 NIO 网络框架
- 自定义协议 - 包含魔数、消息类型、序列化方式等
- 长连接 - 支持连接复用和心跳保活
序列化
- Kryo - 主推的高性能序列化框架
- Hessian - 跨语言序列化支持
- Protostuff - 基于 Protobuf 的 Java 实现
服务治理
- Zookeeper - 分布式协调服务,实现服务注册发现
- 负载均衡 - 支持随机和一致性哈希算法
- 服务分组 - 支持服务的分组和版本管理
框架集成
- Spring - 与 Spring 框架深度集成
- 注解驱动 - 支持注解方式的服务声明和注入
- SPI 机制 - 支持插件化扩展
🚀 RPC 调用流程
服务端启动流程
- 🏗️ 服务实现:编写服务接口的实现类
- 🏷️ 服务标记:使用 @RpcService 注解标记服务
- 📝 服务注册:启动时将服务注册到 Zookeeper
- 👂 监听请求:启动 Netty 服务器监听客户端请求
- ⚡ 处理请求:接收请求,调用本地方法,返回结果
客户端调用流程
- 💉 服务注入:使用 @RpcReference 注解注入服务代理
- 🔍 服务发现:从 Zookeeper 获取可用服务实例列表
- ⚖️ 负载均衡:根据负载均衡算法选择一个服务实例
- 📦 请求封装:将方法调用封装成 RpcRequest 对象
- 🌐 网络传输:通过 Netty 发送请求到服务端
- 📥 结果处理:接收响应,反序列化后返回给调用方
详细时序图
客户端 注册中心(ZK) 服务端
| | |
|------ 1.服务发现 -------->| |
|<----- 2.返回服务列表 ------| |
| | |
|------ 3.建立连接 ------------------------->|
|------ 4.发送RPC请求 ---------------------->|
| | 5.处理请求 |
| | 6.调用本地方法|
|<----- 7.返回响应结果 ----------------------|