一. ????? ? 遠(yuǎn)程通訊協(xié)議的基本原理
網(wǎng)絡(luò)通信需要做的就是將流從一臺(tái)計(jì)算機(jī)傳輸?shù)搅硗庖慌_(tái)計(jì)算機(jī),基于傳輸協(xié)議和網(wǎng)絡(luò) ? IO ? 來實(shí)現(xiàn),其中傳輸協(xié)議比較出名的有 ? http ? 、 ? tcp ? 、 ? udp ? 等等, ? http ? 、 ? tcp ? 、 ? udp ? 都是在基于 ? Socket ? 概念上為某類應(yīng)用場(chǎng)景而擴(kuò)展出的傳輸協(xié)議,網(wǎng)絡(luò) ? IO ? ,主要有 ? bio ? 、 ? nio ? 、 ? aio ? 三種方式,所有的分布式應(yīng)用通訊都基于這個(gè)原理而實(shí)現(xiàn),只是為了應(yīng)用的易用,各種語言通常都會(huì)提供一些更為貼近應(yīng)用易用的應(yīng)用層協(xié)議。
二. ????? ? 應(yīng)用級(jí)協(xié)議 ? Binary-RPC
Binary-RPC ? 是一種和 ? RMI ? 類似的遠(yuǎn)程調(diào)用的協(xié)議,它和 ? RMI ? 的不同之處在于它以標(biāo)準(zhǔn)的二進(jìn)制格式來定義請(qǐng)求的信息 ? ( ? 請(qǐng)求的對(duì)象、方法、參數(shù)等 ? ) ? ,這樣的好處是什么呢,就是在跨語言通訊的時(shí)候也可以使用。
來看下 ? Binary -RPC ? 協(xié)議的一次遠(yuǎn)程通信過程:
?
1 ? 、客戶端發(fā)起請(qǐng)求,按照 ? Binary -RPC ? 協(xié)議將請(qǐng)求信息進(jìn)行填充;
2 ? 、填充完畢后將二進(jìn)制格式文件轉(zhuǎn)化為流,通過傳輸協(xié)議進(jìn)行傳輸;
3 ? 、接收到在接收到流后轉(zhuǎn)換為二進(jìn)制格式文件,按照 ? Binary -RPC ? 協(xié)議獲取請(qǐng)求的信息并進(jìn)行處理;
4 ? 、處理完畢后將結(jié)果按照 ? Binary -RPC ? 協(xié)議寫入二進(jìn)制格式文件中并返回。
???????? ? 問題總結(jié):
1 ? 、傳輸?shù)臉?biāo)準(zhǔn)格式是?
??? ? 標(biāo)準(zhǔn)格式的二進(jìn)制文件。
2 ? 、怎么樣將請(qǐng)求轉(zhuǎn)化為傳輸?shù)牧鳎?
??? ? 將二進(jìn)制格式文件轉(zhuǎn)化為流。
3 ? 、怎么接收和處理流?
??? ? 通過監(jiān)聽的端口獲取到請(qǐng)求的流,轉(zhuǎn)化為二進(jìn)制文件,根據(jù)協(xié)議獲取請(qǐng)求的信息,進(jìn)行處理并將結(jié)果寫入 ? XML ? 中返回。
4 ? 、傳輸協(xié)議是?
Http ? 。
三. ????? ? Hessian ? ——一種實(shí)現(xiàn)遠(yuǎn)程通訊的 ? library
Hessian ? 是由 ? caucho ? 提供的一個(gè)基于 ? binary-RPC ? 實(shí)現(xiàn)的遠(yuǎn)程通訊 ? library ? 。
1 ? 、是基于什么協(xié)議實(shí)現(xiàn)的?
基于 ? Binary-RPC ? 協(xié)議實(shí)現(xiàn)。
2 ? 、怎么發(fā)起請(qǐng)求?
需通過 ? Hessian ? 本身提供的 ? API ? 來發(fā)起請(qǐng)求。
3 ? 、怎么將請(qǐng)求轉(zhuǎn)化為符合協(xié)議的格式的?
Hessian ? 通過其自定義的串行化機(jī)制將請(qǐng)求信息進(jìn)行序列化,產(chǎn)生二進(jìn)制流。
4 ? 、使用什么傳輸協(xié)議傳輸?
Hessian ? 基于 ? Http ? 協(xié)議進(jìn)行傳輸。
5 ? 、響應(yīng)端基于什么機(jī)制來接收請(qǐng)求?
響應(yīng)端根據(jù) ? Hessian ? 提供的 ? API ? 來接收請(qǐng)求。
6 ? 、怎么將流還原為傳輸格式的?
Hessian ? 根據(jù)其私有的串行化機(jī)制來將請(qǐng)求信息進(jìn)行反序列化,傳遞給使用者時(shí)已是相應(yīng)的請(qǐng)求信息對(duì)象了。
7 ? 、處理完畢后怎么回應(yīng)?
??? ? ???????? ? 處理完畢后直接返回, ? hessian ? 將結(jié)果對(duì)象進(jìn)行序列化,傳輸至調(diào)用端。
?
????????? Hessian機(jī)制
?
? 那么 Hessian 就是把 Java 對(duì)象轉(zhuǎn)變成 ? 字節(jié)序列,然后通過 Http 傳輸?shù)? ? 目標(biāo)服務(wù)器上(主機(jī) 2 ),主機(jī) 2 收到這個(gè)字節(jié)序列后,按照一定的協(xié)議標(biāo)準(zhǔn)進(jìn)行反序列,提交給對(duì)應(yīng)的服務(wù)處理。處理完成以后以同樣的方式返回?cái)?shù)據(jù)。
?
現(xiàn)在我們回頭看看例子中的配置( WEB-INF.XML ) :
配置的 Servlet : ? com.caucho.hessian.server.HessianServlet
對(duì)應(yīng)的參數(shù):接口 (home-api) : com.alisoft.enet.hessian.Hello
???????????????????????????? 實(shí)現(xiàn) (home-class): com.alisoft.enet.hessian.HelloImpl
?
?
?
HessianServlet? 中的實(shí)現(xiàn)代碼如下(略過部分代碼):
?
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
InputStream is = request.getInputStream();
OutputStream os = response.getOutputStream();
//輸入流
Hessian2Input in = new Hessian2Input(is);
SerializerFactory serializerFactory = getSerializerFactory();
in.setSerializerFactory(serializerFactory);
//輸出流
AbstractHessianOutput out;
int major = in.read();
int minor = in.read();
out = new Hessian2Output(os);
out.setSerializerFactory(serializerFactory);
_homeSkeleton.invoke(in, out);
?
整個(gè)執(zhí)行步驟如下:
l ?? 接收輸入流,并通過 SerializerFactory 轉(zhuǎn)化為 ?Hessian? 特有的 ? Hessian2Input
l ?? 設(shè)置輸出流,并通過 SerializerFactory 轉(zhuǎn)化為 ?Hessian? 特有的 ? Hessian2Output
l ?? 根據(jù)配置的接口和實(shí)現(xiàn)參數(shù),調(diào)用服務(wù),并把結(jié)果寫入到輸出流 ? Hessian2Output 中
l ??? Out.close()
?
Hessian 遠(yuǎn)程訪問基于序列化和反序列化的方式。當(dāng)程序運(yùn)行時(shí),程序所創(chuàng)建的各種對(duì)象都位于內(nèi)存中,當(dāng)程序運(yùn)行結(jié)束,這些對(duì)象就結(jié)束了生命周期。對(duì)象的序列化主要有兩種用途:
l ?? 把對(duì)象的字節(jié)序列永久地保存到硬盤上,通常是放在一個(gè)文件中。
l ?? 在網(wǎng)絡(luò)上傳輸對(duì)象的字節(jié)序列
?
?
四. ????? ? Hessian ? 源碼分析
以 ? hessian ? 和 ? spring dm server ? 整合環(huán)境為例。
1. ???? ? 客戶端發(fā)起請(qǐng)求
Hessian ? 的這個(gè)遠(yuǎn)程過程調(diào)用,完全使用動(dòng)態(tài)代理來實(shí)現(xiàn)的。有客戶端可以看出。
除去 ? spring ? 對(duì)其的封裝,客戶端主要是通過 ? HessianProxyFactory ? 的 ? create ? 方法就是創(chuàng)建接口的代理類,該類實(shí)現(xiàn)了接口, ? JDK ? 的 ? proxy ? 類會(huì)自動(dòng)用 ? InvocationHandler ? 的實(shí)現(xiàn)類(該類在 ? Hessian ? 中表現(xiàn)為 ? HessianProxy ? )的 ? invoke ? 方法體來填充所生成代理類的方法體。
客戶端系統(tǒng)啟動(dòng)時(shí):
???????? ? 根據(jù) ? serviceUrl ? 和 ? serviceInterface ? 創(chuàng)建代理。
???????? ? HessianProxyFactoryBean ? 類
????????
HessianClientInterceptor ? 類
? ? ?????? ? ???????? ? createHessianProxy(HessianProxyFactory proxyFactory)
?
HessianProxyFactory ? 類
???????? ? ???????? ? public Object create(Class api, String urlName)
?
客戶端調(diào)用 ? hessian ? 服務(wù)時(shí):
?????????????????? ? HessianProxy ? 類的 ? invoke(Object proxy, Method method, Object []args) ? 方法
??????????????????????????? ? String methodName = method.getName();// ? 取得方法名
??????????????????????????? ? Object value = args[0]; // ? 取得傳入?yún)?shù)
??????????????????????????? ? conn = ? sendRequest(mangleName, args) ? ; ????? ? // ? 通過該方法和服務(wù)器端取得連接
?
???????? ? ?????????????????? ? httpConn = (HttpURLConnection) conn;
??????????????????????????? ? code = httpConn.getResponseCode(); ??? ? // ? 發(fā)出請(qǐng)求
?
// ? 等待服務(wù)器端返回相應(yīng)…………
?
???????? ? ?????????????????? ? is = conn.getInputStream();
??????????????????????????? ? Object value = in.readObject(method.getReturnType()); // ? 取得返回值
?
HessianProxy ? 類的 ? URLConnection sendRequest(String methodName, Object []args) ? 方法:
??? ? ???????? ? ???????? ? URLConnection ? ? conn = _factory.openConnection(_url); ????? ? // ? 創(chuàng)建 ? URLConnection ?
???????? ? ?????????????????? ? OutputStream os = conn.getOutputStream();
?
???????? ? ?????????????????? ? AbstractHessianOutput out = _factory.getHessianOutput(os); // ? 封裝為 ? hessian ? 自己的輸入輸出 ? API
???????? ? ?????????????????? ? out.call(methodName, args);
???????? ? ?????????????????? ? return conn;
????????
?
2. ???? ? 服務(wù)器端接收請(qǐng)求并處理請(qǐng)求
服務(wù)器端截獲相應(yīng)請(qǐng)求交給:
org.springframework.remoting.caucho.HessianServiceExporter
具體處理步驟如下:
a) ?????? ? HessianServiceExporter ? 類
(HessianExporter) ? invoke(request.getInputStream(), response.getOutputStream());
?
b) ?????? ? HessianExporter ? 類
(Hessian2SkeletonInvoker) ? this.skeletonInvoker.invoke(inputStream, outputStream);
c) ?????? ? Hessian2SkeletonInvoker ? 類
將輸入輸出封轉(zhuǎn)化為轉(zhuǎn)化為 ? Hessian ? 特有的 ? Hessian2Input ? 和 ? Hessian2Output
????? ? Hessian2Input in = new Hessian2Input(isToUse);
????? ? in.setSerializerFactory(this.serializerFactory);
?
????? ? AbstractHessianOutput out = null;
????? ? int major = in.read();
????? ? int minor = in.read();
????? ? out = new Hessian2Output(osToUse);
????? ? out = new HessianOutput(osToUse);
????? ? out.setSerializerFactory(this.serializerFactory);
????? ? (HessianSkeleton) this.skeleton.invoke(in, out);
?
d) ?????? ? HessianSkeleton ? 類
?????????? ? 讀取方法名
???????? ? String methodName = in.readMethod();
??? ? Method method = getMethod(methodName);
?
?????????? ? 讀取方法參數(shù)
???????? ? Class []args = method.getParameterTypes();
??? ? Object []values = new Object[args.length];
?
?????????? ? 執(zhí)行相應(yīng)方法并取得結(jié)果
???????? ? result = method.invoke(service, values);
?
?????????? ? 結(jié)果寫入到輸出流
???????? ? out.writeObject(result);
????????
總結(jié): ? 由上面源碼分析可知,客戶端發(fā)起請(qǐng)求和服務(wù)器端接收處理請(qǐng)求都是通過 ? hessian ? 自己的 ? API ? 。輸入輸出流都要封裝為 ? hessian ? 自己的 ? Hessian2Input ? 和 ? Hessian2Output ? ,接下來一節(jié)我們將去了解 ? hessian ? 自己封裝的輸入輸出到底做了些什么!
五. ????? ? Hessian ? 的序列化和反序列化實(shí)現(xiàn)
hessian ? 源碼中 ? com.caucho.hessian.io ? 這個(gè)包是 ? hessian ? 實(shí)現(xiàn)序列化與反序列化的核心包。其中 AbstractSerializerFactory ? , ? AbstractHessianOutput ? , ? AbstractSerializer ? , ? AbstractHessianInput ? , AbstractDeserializer ? 是 ? hessian ? 實(shí)現(xiàn)序列化和反序列化的核心結(jié)構(gòu)代碼。
?
1. ???????? ? AbstractSerializerFactory ? ,它有 ? 2 ? 個(gè)抽象方法:
根據(jù)類來決定用哪種序列化工具類
abstract public Serializer getSerializer(Class cl) ? ? throws HessianProtocolException; ?
根據(jù)類來決定用哪種反序列化工具類
abstract public Deserializer getDeserializer(Class cl) ? ? throws HessianProtocolException;
2. ???????? ? SerializerFactory ? 繼承 ? AbstractSerializerFactory ? 。
在 ? SerializerFactory ? 有很多靜態(tài) ? map ? 用來存放類與序列化和反序列化工具類的映射,這樣如果已經(jīng)用過的序列化工具就可以直接拿出來用,不必再重新實(shí)例化工具類。
在 ? SerializerFactory ? 中,實(shí)現(xiàn)了抽象類的 ? getSerializer ? 方法,根據(jù)不同的需要被序列化的類來獲得不同的序列化工具,一共有 ? 17 ? 種序列化工具, ? hessian ? 為不同的類型的 ? java ? 對(duì)象實(shí)現(xiàn)了不同的序列化工具,默認(rèn)的序列化工具是 ? JavaSerializer ? 。
在 ? SerializerFactory ? 中,也實(shí)現(xiàn)了抽象類的 ? getDeserializer ? 方法,根據(jù)不同的需要被反序列化的類來獲得不同的反序列化工具,默認(rèn)的反序列化工具類是 ? JavaDeserializer ? 。
3. ???????? ? HessianOutput ? 繼承 ? AbstractHessianOutput ? 成為序列化輸出流的一種實(shí)現(xiàn)。
它會(huì)實(shí)現(xiàn)很多方法,用來做流輸出。
需要注意的是方法,它會(huì)先調(diào)用 ? serializerFactory ? 根據(jù)類來獲得 ? serializer ? 序列化工具類
public void writeObject(Object object)
throws IOException ?
{ ?
if (object == null) { ?
writeNull(); ?
return; ?
} ?
?
Serializer serializer; ?
?
serializer = ? _serializerFactory.getSerializer(object.getClass()); ? ?
?
serializer.writeObject(object, this); ?
} ?
4. ???????? ? 現(xiàn)在我們來看看 ? AbstractSerializer ? 。
其 ? writeObject ? 是必須在子類實(shí)現(xiàn)的方法, ? AbstractSerializer ? 有 ? 17 ? 種子類實(shí)現(xiàn), ? hessian ? 根據(jù)不同的 java ? 對(duì)象類型來實(shí)現(xiàn)了不同的序列化工具類,其中默認(rèn)的是 ? JavaSerializer ? 。
而 ? JavaSerializer ? 的 ? writeObject ? 方法的實(shí)現(xiàn),遍歷 ? java ? 對(duì)象的數(shù)據(jù)成員,根據(jù)數(shù)據(jù)成員的類型來獲得各自的 ? FieldSerializer ? ,一共有 ? 6 ? 中默認(rèn)的 ? FieldSerializer ? 。
拿默認(rèn)的 ? FieldSerializer ? 舉例,還是調(diào)用 ? AbstractHessianOutput ? 的子類來 ? writeObject ? ,這個(gè)時(shí)候,肯定能找到相應(yīng)的 ? Serializer ? 來做序列化
?
同理可以反推出 ? hessian ? 的反序列化機(jī)制。 ? SerializerFactory ? 可以根據(jù)需要被反序列化的類來獲得反序列化工具類來做反序列化操作。
?
總結(jié):得益于 ? hessian ? 序列號(hào)和反序列化的實(shí)現(xiàn)機(jī)制, ? hessian ? 序列化的速度很快,而且序列化后的字節(jié)數(shù)也較其他技術(shù)少。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
