hprose for java原始碼分析-4

4。1 疑竇叢生

書接上回。上回說到,

從HproseClient。java ————————————- (#0)

hprose for java原始碼分析-4

invokeHandler。handle()開始,將經歷一個漫長的呼叫過程,下面把整個呼叫鏈粘出來,先認識下這個龐然大物。

( >>> 表示呼叫到, 後面 xxx。java,表示原始碼所在檔案,接下來的是函式原始碼 )

>>> HandlerManager。java ————————————- ( #1 )

hprose for java原始碼分析-4

>>> HproseClient。java ————————————————(#2 )

hprose for java原始碼分析-4

>>> HproseClient。java ———————————————— (#3 )

hprose for java原始碼分析-4

534行的呼叫的encode()方法未貼出原始碼,之後會介紹。

>>> HandlerManager。java ————————————- (#4 )

hprose for java原始碼分析-4

>>> HproseClient。java ——————————————- (#5 )

hprose for java原始碼分析-4

>>> HproseClient。java ————————————————(#6)

hprose for java原始碼分析-4

>>> HandlerManager。java ————————————-(#7 )

hprose for java原始碼分析-4

>>> HproseClient。java ————————————————-(#8 )

hprose for java原始碼分析-4

>>> HproseClient。java ——————————————- (#9 )

hprose for java原始碼分析-4

>>> HproseTcpClient。java —————————— (#10)

hprose for java原始碼分析-4

>>> HproseTcpClient。java ———————— (#11)

hprose for java原始碼分析-4

到#11暫告一段落,讓我喘口氣先。這段呼叫步驟太多了,耐心看到這裡的各位看客,都是好樣的,為你點贊。繼續,加油。

能不能簡化一下呢?好像不能,這段呼叫一氣呵成,沒有可以跳過的步驟。然呼叫步驟雖多,每個函式原始碼行數並不多。看來,還得耐心分析一下。

初看這段呼叫,會被幾件事情搞暈:

1)。 #0中的invokeHandler。handle(name, args, context) 與 #1中的 invokeHandler(name, args, context)。

這2處都出現了 invokeHandler,從#0看 invokeHandler是例項物件,從#1看,invokeHandler又是函式。

invokeHandler到底是函式還是例項物件。

2)。 #2,#3又出現2處invokeHandler同名函式,這比較容易理解,這2個是過載函式,因為第3個引數型別不一樣。

3)。 #3中的 beforeFilterHandler。handle(stream。buffer, context) 與 #4中的 beforeFilterHandler(request, context) 2處同名的 beforeFilterHandler, 暈乎乎分不清,它到底是函式還是例項物件。

還有後面 的 afterFilterHandler。handle(request, context) 與 afterFilterHandler(request, context)。

4)。 beforeFilterHandler,與afterFilterHandler,作用是什麼?

5)。 #11中,首次呼叫142行fetch() 函式時,返回的conn為null,於是send不會呼叫。這個呼叫鏈就會一步一步的返回到最初 #0處。而此時,資料還沒有發向網路,RPC呼叫結果並未從伺服器端返回。也就是說,在並未收到伺服器端呼叫結果的情況下,#11處的呼叫鏈開始逐層返回了,而這種返回可能會直接返回到鏈的呼叫最初始處,即 obj。hello(“world”),這個結果是啥呢?第一回說過,在伺服器端未返回結果前,客戶端會處於等待狀態,直到有資料了,客戶端才會返回到最初呼叫處。客戶端是如何等待的,又是在哪一步等待的?

6)。 最讓人頭疼的是 #7中afterFilterHandler(request, context)呼叫完後,後面接了一個。then呼叫,即

afterFilterHandler(request, context)。then(new Func()

同樣beforeFilterHandler也有類似情況。

再沿呼叫鏈仔細看一下,幾乎每處都出現了 。then() 的情況,這究竟是何方神聖?

疑問很多,不過值得期待的是,這段呼叫是整個客戶端的核心部分,這部分弄通了,就掌握了客戶端關鍵,而其它部分是張飛吃豆芽,小菜一碟。

4。2 抽絲剝繭

接下來一個個分析上面的疑問。

1。 invokeHandler同名問題。

事實上,在一個java類裡面,成員變數與方法可以同名。如下面這個類

hprose for java原始碼分析-4

map方法與map成員變數雖是同名的,但java允許這樣做。

不過同名也給我們帶來了困擾,看來,為了使程式碼看起來更清晰些,需要人為避免一些同名出現。

beforeFilterHandler, afterFilterHandler也是這個問題。

因此4。1中的問題1), 3),一個為例項物件,一個為方法。

2。 #2, #3處的過載。看#2處 invokeHandler,它覆蓋了基類(HandlerManager)中的函式,基類中定義的第3個引數型別是HproseContext,但客戶端用的是 ClientContext 型別,所以定義了一個 invokeHandler的

過載函式,來接收 ClientContext型別,即#3處的程式碼。

看到ClientContext,不禁要問,難道還有 ServiceContext?確實有,只不過ServiceContext在伺服器端使用。同樣,伺服器端會遇到類似的過載問題。

由此看來,方法過載雖然好用,但用多了,也會造成困擾,還是慎用吧。當然如果只有幾個過載方法,還是可以的,如果有幾十個,或上百個,想分清楚誰是誰,也是有難度的。

3。 beforeFilterHandler的作用。

#3中,beforeFilterHandler。handle()呼叫前,先呼叫了encode(name,args,context),把所調方法的名稱,引數,寫入了一個流stream中。beforeFilterHandler。handle()作用是,在hprose繼續處理stream之前,準確的說是在呼叫

hprose for java原始碼分析-4

方法前( #6中341行 )

可以先給使用者去做一些處理。預設情況下 beforeFilterHandler引用的是

HandlerManager。defaultBeforeFilterHandler 例項物件,可透過下面的方法來新增外部handle,見下面的程式碼:

HandlerManager。java

hprose for java原始碼分析-4

呼叫addBeforeFilterHandler之後,beforeFilterHandler引用已經改變了,此時再呼叫

beforeFilterHandler。handle()時,首先呼叫的將是外部設定的那個handle了,於是在這個自定義的handle裡,

可以對傳入的ByteBuffer物件做額外處理。FilterHandler介面定義如下:

hprose for java原始碼分析-4

4。 afterFilterHandler的作用。

同樣的道理,對於afterFilterHandler。handle()是指在呼叫 outputFilter方法後( #6中341行 ),可以由外部做的事情,afterFilterHandler 預設情況下引用 HandlerManager 。defaultAfterFilterHandler 例項,透過下面的方法

HandlerManager。java中

hprose for java原始碼分析-4

來改變 afterFilterHandler的引用。

解決了 4。1中幾個疑問,還有2個有待解決,一是 。then 問題,另外一個客戶端如何等待問題?

先解決 。then問題,再來看客戶端等待問題。

請繼續關注下集——何方神聖。