1, 先從protobuf開始吧。
protobuf是一個高效的序列化協(xié)議,protobuf分兩部分,一部分是用c++編寫的protoc編譯器,用于把proto文件編譯為java/c#/go/c++等語言的支持序列化反序列化的對象。

protoc -I [proto文件路徑] --java_out [生成的類文件路徑] [proto文件路徑]
生成的java類都繼承自protobuf-java中的類。
以后有時間分析一下protoc的源碼!??!
2, 如正題,先從源碼中的helloword開始。

下面開始分析server啟動過程以及一個請求的處理過程。
3, 從類名就可以看出使用的構(gòu)造器設(shè)計模式,此模式特別適用于配置參數(shù)特別多的類。lombok中的@Builder注解非常方便。


從源碼中可以看到,此處通過jdk中的spi加載ServerProvider,最終加載到的是NettyServerProvider類。NettyServerProvider的builderForPort返回NettyServerBuilder類。

ServerProvider里的方法不多,用于注冊服務(wù),添加攔截器,初始化server狀態(tài)。
最后調(diào)用build構(gòu)造出server對象。構(gòu)造的過程如下:


ServerImpl維護著整個server的狀態(tài),最關(guān)鍵的屬性如下:
1,ObjectPool<? extends Executor> executorPool:執(zhí)行請求的服務(wù)方法的線程池。
2,InternalHandlerRegistry registry:服務(wù)方法主注冊表,運行時不能修改。
3,HandlerRegistry fallbackRegistry:fallback注冊表,運行時可以動態(tài)修改。
4,List<ServerTransportFilter> transportFilters:監(jiān)聽client連接ready和terminal事件。
5, ServerInterceptor[] interceptors:服務(wù)攔截器,添加順序和執(zhí)行順序相反,服務(wù)方法執(zhí)行時以裝飾器設(shè)計模式嵌入執(zhí)行流程。
6, InternalServer transportServer:NettyServer。
7, Collection<ServerTransport> transports:accept到的client連接。
8, DecompressorRegistry decompressorRegistry:解碼器注冊表。
9, CompressorRegistry compressorRegistry:編碼器注冊表。
10, BinaryLogProvider binlogProvider:記錄log。
11, Channelz channelz:記錄server,channel的狀態(tài)。
12, CallTracer serverCallTracer:統(tǒng)計rpc調(diào)用次數(shù)。
4, server構(gòu)造之后開始調(diào)用start方法啟動。

此處的重點是啟動傳輸層時傳入了ServerListener,用來client連接建立或終結(jié)時從傳輸層回調(diào)server。

netty啟動過程,重點是childHandler設(shè)置的處理client請求的pipeline。

此處的重點是ServerTransportListener,在連接建立和收到client請求數(shù)據(jù)時從傳輸層回調(diào)server。


洗盡鉛華,發(fā)現(xiàn)最終處理client的handler只有NettyServerHandler而已。

從類層次上看以看到NettyServerHandler只是一個解碼器decoder,具體點就是Http2ConnectionHandler,由此可見,grpc的傳輸協(xié)議是http2,相比與http1.1效率有很大提升,據(jù)說主要在兩方面:利用IO多播使一個連接可以請求多個資源,header壓縮,有空詳細分析http2協(xié)議。
在NettyServerHandler的構(gòu)造過程中有一句至關(guān)重要: decoder().frameListener(new FrameListener())。熟悉netty codec機制的一看就明白,就是根據(jù)http2協(xié)議,每次解析到一幀都會通知。

重點是onDataRead,onHeadersRead,onSettingsRead(tcp握手完成)顧名思義。

現(xiàn)在萬事具備了,server已經(jīng)啟動,啟動的過程主要在注冊各種服務(wù),添加服務(wù)攔截器等,初始化netty。
當有請求到來時,ByteToMessageDecoder會按http2協(xié)議解析幀,當收到http header時,

此處最關(guān)鍵的時構(gòu)造了NettyServerStream,此類的作用是一個請求完成后把響應(yīng)信息返回給client,最重要的屬性是WriteQueue writeQueue,響應(yīng)信息的隊列,緩存響應(yīng)信息,等全部處理完,調(diào)用flush把所有響應(yīng)信息返回給client。
另一個重點是通過listener回調(diào)通知server已經(jīng)收到了數(shù)據(jù)包,第一個數(shù)據(jù)包永遠都是header。header都有啥?

最關(guān)鍵的是method,服務(wù)方法的全限定名。
現(xiàn)在的流程從傳輸層轉(zhuǎn)到了server。

此處設(shè)置了一個非常關(guān)鍵的JumpToApplicationThreadServerStreamListener,當IO線程收齊http body之后回調(diào)。

很明顯,找到請求的服務(wù),調(diào)用它。很神奇,只收到header就開始調(diào)用服務(wù)?。?!netty的io是全異步的,調(diào)用的過程中已經(jīng)在接收http body啦。


裝飾器設(shè)計模式的應(yīng)用,套了一層又一層,此處很容易明白為啥服務(wù)攔截器添加順序和執(zhí)行順序相反啦。
終于開始調(diào)用方法了,根據(jù)請求的方法的類型調(diào)用對應(yīng)的ServerCallHandler。

以最簡單又最常見的UNARY為例吧,一個請求跟隨一個響應(yīng)。

此處的call.request(2)至關(guān)重要,2表示應(yīng)該收到2個幀,注釋里解釋里原因。

當收到http body時,通過一大串listener的通知,最后到達onMessage,此時的request已經(jīng)經(jīng)過里protobuf的反序列化,轉(zhuǎn)成里請求對象。
根據(jù)tcp協(xié)議,client發(fā)送完請求后,如果不是長連接,會關(guān)閉輸入端,等待響應(yīng)。一旦輸入端關(guān)閉,就知道所有請求都發(fā)送完啦,終于可以調(diào)用服務(wù)方法啦。
那這個UnaryServerCallListener是怎么被調(diào)用呢。
就在上面的call.request(2)這句啦,



一直循環(huán)直到讀完所有數(shù)據(jù),但是這個循環(huán)本身并不直接操作IO,它只是把CompositeReadableBuffer unprocessed里面的內(nèi)容收起起來判斷是否讀到了需要的數(shù)據(jù)。
毫無疑問,unprocessed里的內(nèi)容是IO線程讀出來的。
此時FrameListener收到header之后正忙著收http body。

通知listener收到了新的數(shù)據(jù)包


把收到的數(shù)據(jù)都放到CompositeReadableBuffer unprocessed緩存起來。
一個在監(jiān)聽幀,然后讀數(shù)據(jù)放到unprocessed里緩存,一個是循環(huán)匯總unprocessed里的數(shù)據(jù),終于交織在一起啦。
等http body讀完之后,開始通知之前建立的一大串listener。中間會經(jīng)過protobuf反序列化的過程,最終到達UnaryServerCallListener.onMessage。

然后等待netty收到輸入關(guān)閉事件,通過一串listener,最終到達UnaryServerCallListener.onHalfClose事件。然后真正的到了執(zhí)行服務(wù)方法的時候,method.invoke(request, responseObserver);服務(wù)方法執(zhí)行完,得到的結(jié)果會回調(diào)responseObserver.onNext方法,






最后觸發(fā)channel的flush,返回響應(yīng)信息。
5, 再縷一下整個請求處理流程。
1,server在啟動netty時傳入了ServerListenerImpl,用于接收client連接建立的回調(diào)通知。
2, netty通知server client連接建立時,server返回給netty的是ServerTransportListenerImpl,用于netty在收到http請求幀時回調(diào)通知server。
3,netty收到http header時創(chuàng)建NettyServerStream,然后通過回調(diào)通知server,server根據(jù)http header里的method屬性查詢請求的服務(wù)方法,給NettyServerStream又設(shè)置一個JumpToApplicationThreadServerStreamListener,用于當收到http body時回調(diào)。
4, 收到http header時開始startCall,UnaryServerCallHandler.startCall時通過調(diào)用ServerCall.request方法,進入MessageDeframer的request方法,然后一直循環(huán)檢查是否收到了指定幀數(shù)的http body,UnaryServerCallHandler.startCall返回UnaryServerCallListener,返回的listener又被wrap到ServerStreamListenerImpl里,wrap之后又被set到JumpToApplicationThreadServerStreamListener里。
5,整個listener鏈已經(jīng)設(shè)置好了,就等著netty收到http body啦。
6, netty最終收齊了http body。然后第4步中startCall里那個循環(huán)檢測到http body收齊了,結(jié)束循環(huán)。
7, 然后開始沿著listener鏈通知下去,請求信息在protobuf反序列化之后最終到達UnaryServerCallListener.onMessage保存起來
8, 等待netty收到輸入端關(guān)閉的事件,然后執(zhí)行服務(wù)方法。
9, 服務(wù)方法執(zhí)行完,響應(yīng)信息通過ServerCallStreamObserverImpl.onNext方法protobuf序列化之后,觸發(fā)netty channel的flush事件,返回響應(yīng)給client。
從請求到響應(yīng)的整個流程結(jié)束?。?!