gRPC如何发起远程调用简介。
在客户端创建一个Stub,blockingStub = GreeterGrpc.newBlockingStub(channel);
调用对应的方法就可以发起远程调用,HelloResponse response = blockingStub.sayHello(request);
。
在sayHello
方法中先创建一个代表远程调用的ClientCall
对象,然后调用ClientCalls
的远程调用帮助方法,并传入ClientCall
对象和请求参数对象。
1 | blockingUnaryCall(channel.newCall(METHOD_SAY_HELLO, callOptions), request); |
1 | public <ReqT, RespT> ClientCall<ReqT, RespT> newCall(MethodDescriptor<ReqT, RespT> method, |
如果之前在创建Channel
的时候有设置Interceptor
,会将Interceptor
和channel(是RealChannel
对象)封装成一个InterceptorChannel
,调用它的newCall方法来创建ClientCall
对象(如果加了HeaderClientInterceptor
这里就是SimpleForwardingClientCall
对象,ClientCall对象也是嵌套的)。
创建好ClientCall
后,经过调用一系列的call方法,在asyncUnaryRequestCall方法中,调用了startCall方法,然后发送数据。
1 | private static <ReqT, RespT> void asyncUnaryRequestCall( |
startCall方法中执行了ClientCall
的start方法,执行该方法后,会执行嵌套的ClientCall
的start方法,在最后一个ClientCall
(ClientCallImpl
对象,RealChannel
创建的)的start方法中进行填充Header,使用transport(NettyClientTransport
对象)来创建stream( NettyClientStream
对象 ),传入Listener(ClientStreamListenerImpl
对象,在收到服务端返回的数据时,对数据进行解码,然后将返回值设置到StreamObserver中)。
在transport创建stream的方法中将CreateStreamCommand
对象(是个Headers Frame)放入WriteQueue
中,WriteQueue
是用来存放往服务端写操作的队列,其中的操作会使用Netty的Channel对象来执行。
startCall方法中
1 | call.start(responseListener, new Metadata.Headers()); |
call.start方法设置listener和请求头。call.request方法中调用stream(NettyClientStream)的request方法,stream的request的方法会将一个RequestMessagesCommand
放入WriteQueue
中,然后刷新这个WriteQueue
,即将里面的数据都发送给服务端。
在sendPayload(param)方法中
1 | InputStream payloadIs = method.streamRequest(payload); |
method就是MethodDescriptor对象描述调用的方法,payload就是传入的参数param。streamRequest方法中return requestMarshaller.stream(requestMessage);将payload转成一个InputSteam(ProtoInputStream)。这里的requestMarshaller是ProtoUtils中的marshaller(parser)方法返回的Marshaller对象,parser是HelloRequest类中PARSER。
然后调用stream的writeMessage方法,这个stream就是之前transport创建的NettyClientStream对象,NettyClientStream继承自Http2ClientStream,Http2ClientStream继承自AbstractStream。writeMessage方法就是AbstractStream中的方法。
1 | public void writeMessage(InputStream message) { |
在framer.writePayload(message)方法中,调用message(ProtoInputStream对象)的drainTo(OutputStream)方法往outputStream(OutputStreamAdapter对象)中写数据。
1 | public int drainTo(OutputStream target) throws IOException { |
这里的message就是最开始调用远程方法sayHello(request)中传过来的参数request(HelloRequest对象)。HelloRequest继承GeneratedMessage,GenenratedMessage继承了AbstractMessage,在AbstractMessage中有writeTo(OutputStream)方法,这里就是调用的该方法,在该方法中,调用了AbstractMessage的父类MessageLite的writeTo(CodedOutputStream)抽象方法,该方法由HelloRequest实现。在HelloRequest的实现中直接调用了CodedOutputStream的writeByte方法,交由protobuf框架来进行处理。
call.halfClose()
方法会往WriteQueue
中加入一个SendGrpcFrameCommand
,并立即刷新。
1 | protected void sendFrame(WritableBuffer frame, boolean endOfStream, boolean flush) { |