实现一个简易RPC框架,通过动态代理、Socket通信、序列化和反射机制,使客户端像调用本地方法一样调用远程服务。1. 定义公共接口HelloService及数据传输对象RpcRequest和RpcResponse;2. 服务端使用ServerSocket监听请求,接收后通过反射调用本地方法并返回结果;3. 客户端通过JDK动态代理拦截方法调用,封装为RpcRequest发送至服务端;4. 服务端执行方法后将结果封装为RpcResponse返回;5. 测试时先启动服务端绑定8888端口,客户端通过代理发起远程调用并输出结果。该框架虽简单,但涵盖了RPC核心流程:代理、网络传输、序列化与反射。

实现一个简单的 RPC(远程过程调用)框架,核心目标是让客户端像调用本地方法一样调用远程服务。我们可以通过 Java 的接口代理、反射、Socket 通信和序列化机制来手写一个轻量级的 RPC 框架。
1. 设计思路与核心组件
一个最简 RPC 框架需要以下几个部分:
- 服务提供者(Server):暴露服务,监听请求,执行方法并返回结果。
- 服务消费者(Client):通过代理调用远程服务。
- 网络通信:使用 Socket 实现客户端和服务端之间的数据传输。
- 序列化:将请求和响应对象序列化为字节流进行传输(这里用 JDK 自带的序列化简化实现)。
- 动态代理 + 反射:客户端通过代理发起调用,服务端通过反射执行具体方法。
2. 定义公共接口与模型
首先定义一个服务接口,客户端和服务端都要依赖它。
public interface HelloService {
String sayHello(String name);
}
再定义一个用于封装 RPC 请求的消息体:
立即学习“Java免费学习笔记(深入)”;
import java.io.Serializable;
public class RpcRequest implements Serializable {
private static final long serialVersionUID = 1L;
private String methodName;
private Class>[] paramTypes;
private Object[] args;
// 构造函数、getter、setter 省略
public RpcRequest() {}
public RpcRequest(String methodName, Class>[] paramTypes, Object[] args) {
this.methodName = methodName;
this.paramTypes = paramTypes;
this.args = args;
}
public String getMethodName() { return methodName; }
public void setMethodName(String methodName) { this.methodName = methodName; }
public Class>[] getParamTypes() { return paramTypes; }
public void setParamTypes(Class>[] paramTypes) { this.paramTypes = paramTypes; }
public Object[] getArgs() { return args; }
public void setArgs(Object[] args) { this.args = args; }
}
响应消息类:
import java.io.Serializable;
public class RpcResponse implements Serializable {
private static final long serialVersionUID = 1L;
private Object result;
public RpcResponse() {}
public RpcResponse(Object result) { this.result = result; }
public Object getResult() { return result; }
public void setResult(Object result) { this.result = result; }
}
3. 服务端实现
服务端启动一个 ServerSocket,监听客户端请求,反序列化请求,通过反射调用本地方法,再把结果序列化返回。
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.lang.reflect.Method;
public class RpcServer {
private int port;
private Object service;
public RpcServer(int port, Object service) {
this.port = port;
this.service = service;
}
public void start() throws IOException {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("RPC 服务器启动,监听端口:" + port);
while (true) {
Socket socket = serverSocket.accept();
handleRequest(socket);
}
}
private void handleRequest(Socket socket) {
try (
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())
) {
RpcRequest request = (RpcRequest) ois.readObject();
Method method = service.getClass().getMethod(
request.getMethodName(),
request.getParamTypes()
);
Object result = method.invoke(service, request.getArgs());
oos.writeObject(new RpcResponse(result));
oos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try { socket.close(); } catch (IOException e) { }
}
}
}
4. 客户端代理实现
客户端通过动态代理生成接口的实现,所有方法调用都会被拦截,转为远程调用。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.io.*;
import java.net.Socket;
public class RpcClientProxy {
public T getProxy(final Class interfaceClass, final String host, final int port) {
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class[]{interfaceClass},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = new Socket(host, port);
try (
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())
) {
RpcRequest request = new RpcRequest(method.getName(), method.getParameterTypes(), args);
oos.writeObject(request);
oos.flush();
RpcResponse response = (RpcResponse) ois.readObject();
return response.getResult();
} finally {
socket.close();
}
}
}
);
}
}
5. 服务实现类(服务提供方)
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "Hello, " + name + "!";
}
}
6. 启动服务端和客户端测试
启动服务端:
public class ServerApp {
public static void main(String[] args) throws IOException {
HelloService helloService = new HelloServiceImpl();
RpcServer server = new RpcServer(8888, helloService);
server.start();
}
}
启动客户端:
public class ClientApp {
public static void main(String[] args) {
RpcClientProxy clientProxy = new RpcClientProxy();
HelloService service = clientProxy.getProxy(HelloService.class, "localhost", 8888);
String result = service.sayHello("World");
System.out.println(result); // 输出: Hello, World!
}
}
7. 注意事项与优化方向
- 序列化效率:JDK 序列化性能较差,可替换为 JSON、Kryo、Protobuf 等。
- 连接管理:每次调用新建 Socket 开销大,可用连接池复用。
- 异常处理:服务端抛出异常时应封装到 RpcResponse 返回。
- 超时机制:客户端应支持设置调用超时。
- 注册中心:真实场景中可通过 ZooKeeper 或 Nacos 管理服务地址。











