java rpc框架核心靠动态代理与socket(或netty)分工协作:代理拦截方法调用并封装为rpcrequest,socket负责可靠传输字节流,二者结合实现“本地式”远程调用。

Java RPC 框架底层让远程调用“看起来像本地调用”,核心靠两块:动态代理屏蔽调用细节,Socket(或 Netty)承载真实通信。它们不是并列关系,而是分工协作——代理负责“怎么发起”,Socket 负责“怎么送达”。
动态代理:把方法调用变成可发送的请求
客户端不直接连服务端,而是通过一个代理对象调用接口方法。这个代理由 Proxy.newProxyInstance() 生成,背后是 InvocationHandler 拦截所有方法调用。
比如你写:
HelloService service = RpcProxy.create(HelloService.class);
String result = service.sayHello("world");
实际执行时,sayHello 并没在本地运行,而是被 InvocationHandler.invoke() 拦下来:
- 获取方法名、参数类型、参数值
- 封装成
RpcRequest对象(含接口名、方法名、参数列表、参数类型数组) - 序列化(如 JDK
ObjectOutputStream或 Protostuff)成字节流 - 交给网络层发出去
关键点:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 代理只关心“我要调什么”,不关心“怎么连”“连谁”
- 它把一次方法调用,标准化为一个结构化请求对象,为网络传输做好准备
Socket:把请求可靠地送到服务端
客户端拿到序列化后的字节流,用 Socket 连接服务端(比如 new Socket("127.0.0.1", 8888)),然后写入输出流:
- 需解决 粘包/半包问题:TCP 是字节流,不能天然区分“一次请求”。常见做法是在协议头加长度字段(如前4字节表示body长度)
- 服务端用
ServerSocket监听,accept()得到Socket,读取完整数据包(先读长度,再读指定字节数) - 反序列化得到
RpcRequest,再根据interfaceName + methodName查找本地实现类(靠服务注册表,比如Map<string object></string>存了HelloService→HelloServiceImpl) - 用反射执行:
method.invoke(target, args) - 把返回值封装进
RpcResponse,序列化后写回客户端 socket 输出流
关键点:
- Socket 是最基础的通信载体,轻量但需手动处理连接、超时、重试、异常断连等
- 生产环境多用 Netty 替代原生 Socket,它内置了编解码器、线程模型、心跳机制,更健壮
两者如何串联起来?
整个链路是单向驱动的:
- 你调用代理对象的方法 → 触发
invoke() -
invoke()构建请求 → 交给RpcClient(封装 Socket 逻辑) -
RpcClient建连、发包、等响应 → 收到字节流后反序列化成RpcResponse -
invoke()返回response.getResult(),对你来说就像本地返回一样
没有中间人,没有魔法——就是“拦截→组装→发→收→还原→返回”。
补充说明:为什么必须配合使用?
- 光有 Socket:每次调用都要手写
socket.getOutputStream().write(...),还要自己解析返回结果,无法复用接口定义,代码散乱难维护 - 光有动态代理:它只是个“假对象”,没网络能力,调用永远停留在本地,根本出不了 JVM
只有把代理作为统一入口,Socket(或 Netty)作为执行通道,再加上序列化和反射,才构成一个最小可行的 RPC 调用闭环。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










