基于Netty实现一个简单的RPC框架涉及到多个步骤,包括定义协议、序列化和反序列化、客户端和服务器的通信等。以下是一个详细的实现过程:
步骤概述
- 定义RPC请求和响应的协议
- 实现序列化和反序列化机制
- 实现服务器端
- 实现客户端
- 实现服务代理和动态代理
1. 定义RPC请求和响应的协议
使用Java对象来定义请求和响应:
java
import java.io.Serializable;
public class RpcRequest implements Serializable {
private static final long serialVersionUID = 1L;
private String className;
private String methodName;
private Class<?>[] parameterTypes;
private Object[] parameters;
// Getters and setters
}
public class RpcResponse implements Serializable {
private static final long serialVersionUID = 1L;
private Object result;
private Throwable error;
// Getters and setters
}
2. 实现序列化和反序列化机制
使用Java原生的序列化机制:
java
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.io.*;
public class RpcEncoder extends MessageToByteEncoder<Object> {
@Override
protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(msg);
oos.flush();
byte[] bytes = bos.toByteArray();
out.writeInt(bytes.length);
out.writeBytes(bytes);
}
}
public class RpcDecoder extends ByteToMessageDecoder {
private final Class<?> genericClass;
public RpcDecoder(Class<?> genericClass) {
this.genericClass = genericClass;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() < 4) {
return;
}
in.markReaderIndex();
int dataLength = in.readInt();
if (in.readableBytes() < dataLength) {
in.resetReaderIndex();
return;
}
byte[] bytes = new byte[dataLength];
in.readBytes(bytes);
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
out.add(ois.readObject());
}
}
3. 实现服务器端
服务器端需要处理客户端的请求,调用相应的服务方法,并返回结果。
java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class RpcServer {
private final Map<String, Object> serviceMap = new HashMap<>();
public void registerService(String interfaceName, Object service) {
serviceMap.put(interfaceName, service);
}
public void start(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new RpcDecoder(RpcRequest.class));
p.addLast(new RpcEncoder());
p.addLast(new RpcServerHandler(serviceMap));
}
});
b.bind(port).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.lang.reflect.Method;
import java.util.Map;
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcRequest> {
private final Map<String, Object> serviceMap;
public RpcServerHandler(Map<String, Object> serviceMap) {
this.serviceMap = serviceMap;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, RpcRequest request) throws Exception {
RpcResponse response = new RpcResponse();
try {
Object service = serviceMap.get(request.getClassName());
if (service == null) {
throw new RuntimeException("Service not found: " + request.getClassName());
}
Method method = service.getClass().getMethod(request.getMethodName(), request.getParameterTypes());
Object result = method.invoke(service, request.getParameters());
response.setResult(result);
} catch (Throwable t) {
response.setError(t);
}
ctx.writeAndFlush(response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
4. 实现客户端
客户端需要发送RPC请求并接收响应。
java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.lang.reflect.Proxy;
public class RpcClient {
private final String host;
private final int port;
public RpcClient(String host, int port) {
this.host = host;
this.port = port;
}
public <T> T create(Class<T> serviceClass) {
return (T) Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class<?>[]{serviceClass}, new RpcClientProxy(host, port, serviceClass));
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class RpcClientHandler extends SimpleChannelInboundHandler<RpcResponse> {
private RpcResponse response;
@Override
protected void channelRead0(ChannelHandlerContext ctx, RpcResponse response) throws Exception {
this.response = response;
}
public RpcResponse getResponse() {
return response;
}
}
5. 实现服务代理和动态代理
使用动态代理来简化客户端的调用逻辑。
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class RpcClientProxy implements InvocationHandler {
private final String host;
private final int port;
private final Class<?> serviceClass;
public RpcClientProxy(String host, int port, Class<?> serviceClass) {
this.host = host;
this.port = port;
this.serviceClass = serviceClass;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
RpcRequest request = new RpcRequest();
request.setClassName(serviceClass.getName());
request.setMethodName(method.getName());
request.setParameterTypes(method.getParameterTypes());
request.setParameters(args);
RpcClientHandler handler = new RpcClientHandler();
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new RpcEncoder());
p.addLast(new RpcDecoder(RpcResponse.class));
p.addLast(handler);
}
});
Channel channel = b.connect(host, port).sync().channel();
channel.writeAndFlush(request).sync();
CountDownLatch latch = new CountDownLatch(1);
handler.channelReadComplete(channel.pipeline().lastContext(), latch);
latch.await(10, TimeUnit.SECONDS);
RpcResponse response = handler.getResponse();
if (response.getError() != null) {
throw response.getError();
}
return response.getResult();
} finally {
group.shutdownGracefully();
}
}
}
使用示例
- 定义服务接口和实现:
java
public interface HelloService {
String hello(String name);
}
public class HelloServiceImpl implements HelloService {
@Override
public String hello(String name) {
return "Hello, " + name;
}
}
- 启动服务器:
java
public class RpcServerMain {
public static void main(String[] args) throws Exception {
RpcServer server = new RpcServer();
server.registerService(HelloService.class.getName(), new HelloServiceImpl());
server.start(8080);
}
}
- 客户端调用:
java
public class RpcClientMain {
public static void main(String[] args) {
RpcClient client = new RpcClient("localhost", 8080);
HelloService helloService = client.create(HelloService.class);
String result = helloService.hello("World");
System.out.println(result);
}
}
通过以上步骤,您可以实现一个基于Netty的简单RPC框架。这个框架包括了基本的序列化和反序列化机制、客户端和服务器的通信、服务注册和调用等功能。