hprose for java 教程_hprose for java源码分析-4
4.1 疑竇叢生
書接上回。上回說到,
從HproseClient.java ------------------------- (#0)
invokeHandler.handle()開始,將經(jīng)歷一個漫長的調(diào)用過程,下面把整個調(diào)用鏈粘出來,先認(rèn)識下這個龐然大物。
( >>> 表示調(diào)用到, 后面 xxx.java,表示源代碼所在文件,接下來的是函數(shù)源碼 )
>>> HandlerManager.java ----------------------- ( #1 )
>>> HproseClient.java ------------------------------(#2 )
>>> HproseClient.java ------------------------------ (#3 )
534行的調(diào)用的encode()方法未貼出源碼,之后會介紹。
>>> HandlerManager.java ----------------------- (#4 )
>>> HproseClient.java ----------------------------- (#5 )
>>> HproseClient.java ------------------------------(#6)
>>> HandlerManager.java -------------------------(#7 )
>>> HproseClient.java -------------------------------(#8 )
>>> HproseClient.java ----------------------------- (#9 )
>>> HproseTcpClient.java ------------------ (#10)
>>> HproseTcpClient.java ---------------- (#11)
到#11暫告一段落,讓我喘口氣先。這段調(diào)用步驟太多了,耐心看到這里的各位看客,都是好樣的,為你點贊。繼續(xù),加油。
能不能簡化一下呢?好像不能,這段調(diào)用一氣呵成,沒有可以跳過的步驟。然調(diào)用步驟雖多,每個函數(shù)源碼行數(shù)并不多。看來,還得耐心分析一下。
初看這段調(diào)用,會被幾件事情搞暈:
1). #0中的invokeHandler.handle(name, args, context) 與 #1中的 invokeHandler(name, args, context)。
這2處都出現(xiàn)了 invokeHandler,從#0看 invokeHandler是實例對象,從#1看,invokeHandler又是函數(shù)。
invokeHandler到底是函數(shù)還是實例對象。
2). #2,#3又出現(xiàn)2處invokeHandler同名函數(shù),這比較容易理解,這2個是重載函數(shù),因為第3個參數(shù)類型不一樣。
3). #3中的 beforeFilterHandler.handle(stream.buffer, context) 與 #4中的 beforeFilterHandler(request, context) 2處同名的 beforeFilterHandler, 暈乎乎分不清,它到底是函數(shù)還是實例對象。
還有后面 的 afterFilterHandler.handle(request, context) 與 afterFilterHandler(request, context)。
4). beforeFilterHandler,與afterFilterHandler,作用是什么?
5). #11中,首次調(diào)用142行fetch() 函數(shù)時,返回的conn為null,于是send不會調(diào)用。這個調(diào)用鏈就會一步一步的返回到最初 #0處。而此時,數(shù)據(jù)還沒有發(fā)向網(wǎng)絡(luò),RPC調(diào)用結(jié)果并未從服務(wù)器端返回。也就是說,在并未收到服務(wù)器端調(diào)用結(jié)果的情況下,#11處的調(diào)用鏈開始逐層返回了,而這種返回可能會直接返回到鏈的調(diào)用最初始處,即 obj.hello("world"),這個結(jié)果是啥呢?第一回說過,在服務(wù)器端未返回結(jié)果前,客戶端會處于等待狀態(tài),直到有數(shù)據(jù)了,客戶端才會返回到最初調(diào)用處。客戶端是如何等待的,又是在哪一步等待的?
6). 最讓人頭疼的是 #7中afterFilterHandler(request, context)調(diào)用完后,后面接了一個.then調(diào)用,即
afterFilterHandler(request, context).then(new Func()
同樣beforeFilterHandler也有類似情況。
再沿調(diào)用鏈仔細(xì)看一下,幾乎每處都出現(xiàn)了 .then() 的情況,這究竟是何方神圣?
疑問很多,不過值得期待的是,這段調(diào)用是整個客戶端的核心部分,這部分弄通了,就掌握了客戶端關(guān)鍵,而其它部分是張飛吃豆芽,小菜一碟。
4.2 抽絲剝繭
接下來一個個分析上面的疑問。
1. invokeHandler同名問題。
事實上,在一個java類里面,成員變量與方法可以同名。如下面這個類
map方法與map成員變量雖是同名的,但java允許這樣做。
不過同名也給我們帶來了困擾,看來,為了使代碼看起來更清晰些,需要人為避免一些同名出現(xiàn)。
beforeFilterHandler, afterFilterHandler也是這個問題。
因此4.1中的問題1), 3),一個為實例對象,一個為方法。
2. #2, #3處的重載。看#2處 invokeHandler,它覆蓋了基類(HandlerManager)中的函數(shù),基類中定義的第3個參數(shù)類型是HproseContext,但客戶端用的是 ClientContext 類型,所以定義了一個 invokeHandler的
重載函數(shù),來接收 ClientContext類型,即#3處的代碼。
看到ClientContext,不禁要問,難道還有 ServiceContext?確實有,只不過ServiceContext在服務(wù)器端使用。同樣,服務(wù)器端會遇到類似的重載問題。
由此看來,方法重載雖然好用,但用多了,也會造成困擾,還是慎用吧。當(dāng)然如果只有幾個重載方法,還是可以的,如果有幾十個,或上百個,想分清楚誰是誰,也是有難度的。
3. beforeFilterHandler的作用。
#3中,beforeFilterHandler.handle()調(diào)用前,先調(diào)用了encode(name,args,context),把所調(diào)方法的名稱,參數(shù),寫入了一個流stream中。beforeFilterHandler.handle()作用是,在hprose繼續(xù)處理stream之前,準(zhǔn)確的說是在調(diào)用
方法前( #6中341行 )
可以先給用戶去做一些處理。默認(rèn)情況下 beforeFilterHandler引用的是
HandlerManager.defaultBeforeFilterHandler 實例對象,可通過下面的方法來添加外部handle,見下面的代碼:
HandlerManager.java
調(diào)用addBeforeFilterHandler之后,beforeFilterHandler引用已經(jīng)改變了,此時再調(diào)用
beforeFilterHandler.handle()時,首先調(diào)用的將是外部設(shè)置的那個handle了,于是在這個自定義的handle里,
可以對傳入的ByteBuffer對象做額外處理。FilterHandler接口定義如下:
4. afterFilterHandler的作用。
同樣的道理,對于afterFilterHandler.handle()是指在調(diào)用 outputFilter方法后( #6中341行 ),可以由外部做的事情,afterFilterHandler 默認(rèn)情況下引用 HandlerManager .defaultAfterFilterHandler 實例,通過下面的方法
HandlerManager.java中
來改變 afterFilterHandler的引用。
解決了 4.1中幾個疑問,還有2個有待解決,一是 .then 問題,另外一個客戶端如何等待問題?
先解決 .then問題,再來看客戶端等待問題。
請繼續(xù)關(guān)注下集--何方神圣。
總結(jié)
以上是生活随笔為你收集整理的hprose for java 教程_hprose for java源码分析-4的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Flask mysql 模版传参_Fla
- 下一篇: java批量提取文件夹名称_bat 批量