Jaws:从零构建一个“五脏俱全“的 Java RPC 框架

📅 2026/7/20 11:50:55 👁️ 阅读次数 📝 编程学习
Jaws:从零构建一个“五脏俱全“的 Java RPC 框架

Java 17|Netty 4.1|Spring Boot 3.5|SPI 全可插拔|开箱即用

在 Java RPC 的世界里,Dubbo 和 gRPC 早已是家喻户晓的名字。但当你真正去读它们的源码时,往往会陷入几十万行代码的汪洋——核心逻辑被淹没在大量的兼容性代码、扩展点和历史包袱中。

如果你渴望有一个 RPC 框架,代码量可控、架构清晰、每一行都有意义,同时又不失生产级该有的核心能力——那么 Jaws 正是为此而生。

🎯 为什么需要 Jaws?

痛点一:RPC 框架"会用但不懂"

大多数开发者对 RPC 框架的使用停留在配置层面——加个注解、写个 YAML、服务就跑起来了。但背后的协议编解码、服务注册发现、负载均衡、容错机制,几乎是黑盒。

面试被问到"RPC 框架原理"时,你能讲清楚几层?

痛点二:生产级能力不是"可选项"

很多教学型 RPC Demo 只实现了最基本的调用链路,缺少:

  • 优雅停机(发布时丢请求)
  • 泛化调用(网关无法依赖每个服务的接口 JAR)
  • 可观测性(链路追踪和指标采集)
  • 方法级别配置(不同方法不同超时/重试策略)
  • 主流注册中心适配(Nacos / ZooKeeper 双支持,一键切换)

这些在生产环境中都是刚需。

痛点三:Spring Boot 集成体验参差不齐

有些 RPC 框架的 Spring Boot 集成还停留在 XML 配置或复杂的 Bean 定义阶段。开发者需要的是:两个注解搞定一切

🚀 项目亮点

✨ 1. 自定义二进制协议

基于 Netty 实现的jaws二进制协议,结构清晰,编解码过程完全透明:

┌──────────┬──────────┬──────────┬──────────────┬──────────┬──────────┐ │ magic │ type │ id │ serialization│ status │ body │ │ 2 bytes │ 1 byte │ 8 bytes │ 1 byte │ 1 byte │ variable │ └──────────┴──────────┴──────────┴──────────────┴──────────┴──────────┘

支持fastjson2hessian2两种序列化方式,可通过配置一键切换。

🏗️ 2. 双注册中心支持

注册中心依赖说明
ZooKeeperjaws-registry-zookeeper基于 Curator 5.9,临时节点 + 心跳续约
Nacosjaws-registry-nacos基于 Nacos 3.2.2,支持心跳续约与失败重连

切换注册中心只需更换一个 Maven 依赖和一行配置,业务代码零改动。

🔍 3. 五种负载均衡策略

策略适用场景
Random默认,简单高效
RoundRobin均匀分配
LeastActive热点感知,慢节点自动降权
ShortestResponse响应时间感知,选择预估最快的节点
ConsistentHash相同参数路由到同一节点,适合缓存场景

所有策略均通过 SPI 可插拔,你可以轻松实现自定义策略。

🛡️ 4. 高可用容错

  • Failover— 调用失败自动切换到其他节点,可配置重试次数
  • Failfast— 快速失败,适用于非幂等写操作

⚙️ 5. 四阶段优雅停机

这是很多 RPC 教程忽略但生产环境至关重要的能力。Jaws 实现了完整的停机流程,确保零请求丢失、零损伤发布

Phase 1: stopAccept() 关闭 ServerChannel,不再 accept 新连接 Phase 2: awaitInactiveRequests() 轮询 activeRequests 计数器,等待在途请求完成(默认 10s) Phase 3: unregister() 从注册中心注销所有服务 URL Phase 4: unexport() → destroy() 移除 Provider、关闭连接、释放 EventLoopGroup 和线程池

验证方式

# 启动 Provider./run-sample.sh provider# 另开终端运行 Consumer./run-sample.sh consumer# 发送 SIGTERM 信号,观察四阶段日志jps|grepSampleProvider# 找到 PIDkill-TERM<PID># Provider 日志依次输出:# [GracefulShutdown] Phase 1: Stop accepting new requests# [GracefulShutdown] Phase 2: Waiting for in-flight requests to complete# [GracefulShutdown] Phase 3: Unregister from registry# [GracefulShutdown] Phase 4: Close connections and release resources

🎨 6. 泛化调用

无需依赖 Provider 的接口 JAR 包即可发起 RPC 调用。API 网关、测试平台、Mock 服务的必备能力:

// Spring Boot 注解方式@JawsReference(generic=true,serviceInterface="com.example.DemoService")privateGenericServicedemoService;// 调用Objectresult=demoService.$invoke("hello",newString[]{"java.lang.String"},newObject[]{"jaws"});

Provider 端自动完成 Map↔POJO 参数转换,调用方完全无感知。

📊 7. 可观测性

引入jaws-observability-spring-boot-starter即可获得完整的可观测性能力:

能力实现说明
链路追踪Micrometer Tracing + OpenTelemetryW3C TraceContext 格式自动传播,全链路 traceId 一致
指标采集MicrometerRPC 调用次数、成功率、耗时分布、活跃请求数,sidetag 区分 consumer/provider
日志关联OTel 日志桥接traceId/spanId 自动注入 MDC,无需手动处理

无需额外代码,Filter SPI 自动生效。

💡 8. 方法级别配置

全局配置不够精细?Jaws 支持在消费端为单个方法设置独立的超时和重试策略:

@JawsReference(methods={@Method(name="hello",timeout=5000,retries=3),// 这个方法单独配置@Method(name="getUser",timeout=500)// 这个方法快速失败})privateDemoServicedemoService;

🔌 9. injvm 协议

JVM 内部直调,零网络开销,适合本地开发和单元测试:

./run-sample.sh injvm

无需任何中间件,一行命令即可运行。

🧰 10. RpcContext

消费端可获取实际调用的服务端地址,提供端可获取调用方 IP:

// Consumer 端URLserverUrl=RpcContext.getContext().getServerUrl();// Provider 端StringcallerIp=RpcContext.getContext().getCallerIp();

🏛️ 架构设计

jaws-parent ├── jaws-core # 核心:协议抽象、SPI、序列化、集群、路由、Filter、配置 ├── jaws-transport-netty # Netty 4.1 传输层实现 ├── jaws-registry-zookeeper # ZooKeeper 注册中心 ├── jaws-registry-nacos # Nacos 3.x 注册中心 ├── jaws-extensions # 可观测性:Micrometer 指标 + OpenTelemetry 链路追踪 ├── jaws-spring-boot │ ├── jaws-spring-boot-starter # Spring Boot 自动配置 │ └── jaws-observability-spring-boot-starter # 可观测性自动装配 └── jaws-samples ├── jaws-sample-api # 接口定义 ├── jaws-sample-injvm # injvm 协议示例(无需 ZK) ├── jaws-sample-provider # 服务提供者(ZooKeeper) ├── jaws-sample-consumer # 服务消费者 + 泛化调用 ├── jaws-sample-provider-boot # Spring Boot Provider(Nacos) ├── jaws-sample-consumer-boot # Spring Boot Consumer └── jaws-sample-benchmark # 性能基准测试

核心设计理念

  1. SPI 全可插拔:Protocol、Cluster、LoadBalance、Filter、Serialization 等所有核心组件均通过@SPI+@Activation机制可插拔,替换任何一层不影响其他模块
  2. 分层解耦:core 保持轻量,extensions 承载附加功能,starter 负责自动装配
  3. 配置模型统一:URL 参数 → ServiceConfig/ReferenceConfig → Spring YAML,三层配置自动映射

🎓 学习价值

对于想理解 RPC 原理的开发者

  • ✅ 从零实现协议编解码,理解"网络上传的是什么"
  • ✅ 手写服务注册发现,理解"服务怎么找到对方"
  • ✅ 五种负载均衡策略实现,理解"请求怎么分配"
  • ✅ 四阶段优雅停机,理解"服务下线怎么不丢请求"

对于需要轻量 RPC 方案的团队

  • ✅ Spring Boot 两个注解开箱即用
  • ✅ 双注册中心(ZK/Nacos)自由选择
  • ✅ 泛化调用支持网关和测试平台场景
  • ✅ 可观测性 starter 一键引入

对于架构师

  • ✅ SPI 扩展点设计模式参考
  • ✅ 自定义二进制协议设计
  • ✅ 优雅停机与在途请求管理
  • ✅ 依赖版本统一管理(核心 jar 足够精简)

🚦 快速开始

前置要求

  • Java 17+
  • Maven 3.8+(或使用内置./mvnw
  • ZooKeeper 3.9+ 或 Nacos 3.x

三步启动

1. 编译项目

gitclone https://github.com/javahongxi/jaws.gitcdjaws ./mvnwinstall-DskipTests

2. 引入依赖

<dependency><groupId>org.hongxi</groupId><artifactId>jaws-spring-boot-starter</artifactId><version>${jaws.version}</version></dependency><dependency><groupId>org.hongxi</groupId><artifactId>jaws-registry-nacos</artifactId><version>${jaws.version}</version></dependency>

3. 发布与引用服务

Provider:

@EnableJaws@SpringBootApplicationpublicclassProviderApplication{publicstaticvoidmain(String[]args){SpringApplication.run(ProviderApplication.class,args);}}@JawsServicepublicclassDemoServiceImplimplementsDemoService{@OverridepublicStringhello(Stringname){return"hello "+name;}}

Consumer:

@ComponentpublicclassMyRunnerimplementsCommandLineRunner{@JawsReferenceprivateDemoServicedemoService;@Overridepublicvoidrun(String...args){System.out.println(demoService.hello("jaws"));}}

一键运行示例

# injvm 协议(无需中间件)./run-sample.sh injvm# 完整 RPC 调用(需要 ZK)./run-sample.sh run# 性能基准测试./run-sample.sh bench-jaws# 自定义参数THREADS=16DURATION=20./run-sample.sh bench-jaws

🏆 技术栈

组件技术版本
语言Java17
网络Netty4.1.132
注册中心ZooKeeper + Curator3.9 / 5.9
注册中心Nacos3.2.2
序列化fastjson2 / hessian-lite2.0.62 / 4.0.5
框架集成Spring Boot3.5
可观测性Micrometer + OpenTelemetry1.14 / 1.48
工具Guava33.6

🔗 相关链接

  • 📦项目地址: https://github.com/javahongxi/jaws
  • 🌐作者主页: hongxi.org
  • 📚Java 全栈研究: whatsmars
  • ☁️微服务最佳实践: spring-cloud-samples
  • 📖Spring Boot: https://spring.io/projects/spring-boot
  • 📡Netty: https://netty.io
  • 🌐Nacos: https://nacos.io

🤝 贡献指南

欢迎提交 Issue 和 PR!如果你:

  • 发现 Bug 或有更好的实现方案
  • 想添加新的容错策略或负载均衡算法
  • 希望支持更多序列化方式或注册中心
  • 对性能优化有经验或建议

请随时参与贡献,让 Jaws 成为学习 RPC 原理的最佳参考项目!


© hongxi.org| 以生产级标准,打造最清晰的 Java RPC 框架实现


📝 结语

Jaws 不是要取代 Dubbo 或 gRPC,而是回答一个问题:一个生产级 RPC 框架,最少需要多少代码?

答案是:2万行 Java。

从协议设计到服务发现,从负载均衡到优雅停机,从泛化调用到链路追踪——每一个模块都经过精心设计,每一行代码都有实际意义。没有几十万行的历史包袱,没有看不懂的"魔法"。

如果你正在:

  • 🎯 想深入理解 RPC 框架的核心原理
  • 🚀 需要一个轻量级但功能完整的 RPC 方案
  • 🏗️ 学习 SPI 扩展点设计和自定义协议实现
  • 📚 寻找一个代码量可控、可以通读的框架源码

Star ⭐ Jaws,开启你的 RPC 原理探索之旅!

gitclone https://github.com/javahongxi/jaws.gitcdjaws ./run-sample.sh injvm

让我们一起探索 RPC 框架的本质!🦈