由于netty通信是异步的,客户端请求之后就不再阻塞等待服务端的结果返回了,客户端可以去做其他的事情,而服务端处理完之后会将响应结果输出给客户端,这些客户端并不知道这个响应结果是属于哪次请求的结果。所有需要一套机制去实现响应结果隶属于是属于哪次调用的结果。
通过netty客户端请求服务端流程如下:
下面用代码实现一次完整的,rpc通过netty调用之后,找到对应请求的response:
首先定义一个netty客户端:
public class InvokerClient {
private static Channel channel;
public void init() throws Exception {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(new NioEventLoopGroup()).channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 处理来自服务端的响应信息
socketChannel.pipeline().addLast(new ReceiveHandle());
}
});
ChannelFuture cf = bootstrap.connect("127.0.0.1", 3344).sync();
channel = cf.channel();
}
public Object call(Request request) {
RequestFactory.put(request.getSeq(), null);
channel.writeAndFlush("hello");
return RequestFactory.getResponse(request.getSeq());
}
}
其中Request是请求对象:
public class Request {
private static final UUID uuid = UUID.randomUUID();
//生成一个唯一请求id,netty的返回响应结果时也会带上此id,从而把请求与响应结果绑定了
private String seq = uuid.toString();
private Object object;
public Object getObject() {
return object;
}
public Request setObject(Object object) {
this.object = object;
return this;
}
public String getSeq() {
return seq;
}
}
ReceiveHandle
用于客户端专门处理服务端返回数据的handle
public class ReceiveHandle extends SimpleChannelInboundHandler {
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
RequestFactory.put(o.getSeq(),o);
}
}
RequestFactory
是请求工厂,专门放对应请求的seq,其中value为响应的返回结果
public class RequestFactory {
private static final Map<String, Object> map = new ConcurrentHashMap<String, Object>();
public static void put(String uuid, Object object) {
map.put(uuid, object);
}
public static Object get(String uuid) {
return map.get(uuid);
}
}
从而一次完整的rpc异步调用,对应的响应结果获取代码结束。原理就是请求时生成一个唯一请求id,然后缓存起来,netty返回响应结果时,也带上这个id,从来可以识别响应结果对应着那个请求