Hessian 原理分析
一.??????遠程通訊協議的基本原理
網絡通信需要做的就是將流從一臺計算機傳輸到另外一臺計算機,基于傳輸協議和網絡 IO 來實現,其中傳輸協議比較出名的有 http 、 tcp 、 udp 等等, http 、 tcp 、 udp 都是在基于 Socket 概念上為某類應用場景而擴展出的傳輸協議,網絡 IO ,主要有 bio 、 nio 、 aio 三種方式,所有的分布式應用通訊都基于這個原理而實現,只是為了應用的易用,各種語言通常都會提供一些更為貼近應用易用的應用層協議。
二.??????應用級協議?Binary-RPC
Binary-RPC 是一種和 RMI 類似的遠程調用的協議,它和 RMI 的不同之處在于它以標準的二進制格式來定義請求的信息 ( 請求的對象、方法、參數等 ) ,這樣的好處是什么呢,就是在跨語言通訊的時候也可以使用。
來看下 Binary -RPC 協議的一次遠程通信過程:
?
1 、客戶端發起請求,按照 Binary -RPC 協議將請求信息進行填充;
2 、填充完畢后將二進制格式文件轉化為流,通過傳輸協議進行傳輸;
3 、接收到在接收到流后轉換為二進制格式文件,按照 Binary -RPC 協議獲取請求的信息并進行處理;
4 、處理完畢后將結果按照 Binary -RPC 協議寫入二進制格式文件中并返回。
?????????問題總結:
1 、傳輸的標準格式是?
??? 標準格式的二進制文件。
2 、怎么樣將請求轉化為傳輸的流?
??? 將二進制格式文件轉化為流。
3 、怎么接收和處理流?
??? 通過監聽的端口獲取到請求的流,轉化為二進制文件,根據協議獲取請求的信息,進行處理并將結果寫入 XML 中返回。
4 、傳輸協議是?
Http 。
三.??????Hessian?——一種實現遠程通訊的?library
Hessian 是由 caucho 提供的一個基于 binary-RPC 實現的遠程通訊 library 。
1 、是基于什么協議實現的?
基于 Binary-RPC 協議實現。
2 、怎么發起請求?
需通過 Hessian 本身提供的 API 來發起請求。
3 、怎么將請求轉化為符合協議的格式的?
Hessian 通過其自定義的串行化機制將請求信息進行序列化,產生二進制流。
4 、使用什么傳輸協議傳輸?
Hessian 基于 Http 協議進行傳輸。
5 、響應端基于什么機制來接收請求?
響應端根據 Hessian 提供的 API 來接收請求。
6 、怎么將流還原為傳輸格式的?
Hessian 根據其私有的串行化機制來將請求信息進行反序列化,傳遞給使用者時已是相應的請求信息對象了。
7 、處理完畢后怎么回應?
??? ???????? 處理完畢后直接返回, hessian 將結果對象進行序列化,傳輸至調用端。
四.??????Hessian?源碼分析
以 hessian 和 spring dm server 整合環境為例。
Hessian 的這個遠程過程調用,完全使用動態代理來實現的。有客戶端可以看出。
除去 spring 對其的封裝,客戶端主要是通過 HessianProxyFactory 的 create 方法就是創建接口的代理類,該類實現了接口, JDK 的 proxy 類會自動用 InvocationHandler 的實現類(該類在 Hessian 中表現為 HessianProxy )的 invoke 方法體來填充所生成代理類的方法體。
客戶端系統啟動時:
???????? 根據 serviceUrl 和 serviceInterface 創建代理。
???????? HessianProxyFactoryBean 類
????????
HessianClientInterceptor 類
? ?????? ???????? createHessianProxy(HessianProxyFactory proxyFactory)
?
HessianProxyFactory 類
???????? ???????? public Object create(Class api, String urlName)
?
客戶端調用?hessian?服務時:
???????????????????HessianProxy?類的 invoke(Object proxy, Method method, Object []args)?方法
??????????????????????????? String methodName = method.getName();// 取得方法名
??????????????????????????? Object value = args[0]; // 取得傳入參數
??????????????????????????? conn = sendRequest(mangleName, args) ;????? // 通過該方法和服務器端取得連接
?
???????? ?????????????????? httpConn = (HttpURLConnection) conn;
??????????????????????????? code = httpConn.getResponseCode();??? // 發出請求
?
// 等待服務器端返回相應…………
?
???????? ?????????????????? is = conn.getInputStream();
??????????????????????????? Object value = in.readObject(method.getReturnType()); // 取得返回值
?
HessianProxy?類的 URLConnection sendRequest(String methodName, Object []args)?方法:
??? ???????? ???????? URLConnection? conn = _factory.openConnection(_url);????? // 創建 URLConnection?
???????? ?????????????????? OutputStream os = conn.getOutputStream();
?
???????? ?????????????????? AbstractHessianOutput out = _factory.getHessianOutput(os); // 封裝為 hessian 自己的輸入輸出 API
???????? ?????????????????? out.call(methodName, args);
???????? ?????????????????? return conn;
????????
?
服務器端截獲相應請求交給:
org.springframework.remoting.caucho.HessianServiceExporter
具體處理步驟如下:
a)?????? HessianServiceExporter 類
(HessianExporter) invoke(request.getInputStream(), response.getOutputStream());
?
b)?????? HessianExporter 類
(Hessian2SkeletonInvoker) this.skeletonInvoker.invoke(inputStream, outputStream);
c)?????? Hessian2SkeletonInvoker 類
將輸入輸出封轉化為轉化為 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);
?
?????????? 讀取方法參數
???????? Class []args = method.getParameterTypes();
??? Object []values = new Object[args.length];
?
?????????? 執行相應方法并取得結果
???????? result = method.invoke(service, values);
?
?????????? 結果寫入到輸出流
???????? out.writeObject(result);
????????
總結:?由上面源碼分析可知,客戶端發起請求和服務器端接收處理請求都是通過 hessian 自己的 API 。輸入輸出流都要封裝為 hessian 自己的 Hessian2Input 和 Hessian2Output ,接下來一節我們將去了解 hessian 自己封裝的輸入輸出到底做了些什么!
五.??????Hessian?的序列化和反序列化實現
hessian 源碼中 com.caucho.hessian.io 這個包是 hessian 實現序列化與反序列化的核心包。其中 AbstractSerializerFactory , AbstractHessianOutput , AbstractSerializer , AbstractHessianInput , AbstractDeserializer 是 hessian 實現序列化和反序列化的核心結構代碼。
?
根據類來決定用哪種序列化工具類
abstract public Serializer getSerializer(Class cl)? throws HessianProtocolException;?
根據類來決定用哪種反序列化工具類
abstract public Deserializer getDeserializer(Class cl)? throws HessianProtocolException;
在 SerializerFactory 有很多靜態 map 用來存放類與序列化和反序列化工具類的映射,這樣如果已經用過的序列化工具就可以直接拿出來用,不必再重新實例化工具類。
在 SerializerFactory 中,實現了抽象類的 getSerializer 方法,根據不同的需要被序列化的類來獲得不同的序列化工具,一共有 17 種序列化工具, hessian 為不同的類型的 java 對象實現了不同的序列化工具,默認的序列化工具是 JavaSerializer 。
在 SerializerFactory 中,也實現了抽象類的 getDeserializer 方法,根據不同的需要被反序列化的類來獲得不同的反序列化工具,默認的反序列化工具類是 JavaDeserializer 。
它會實現很多方法,用來做流輸出。
需要注意的是方法,它會先調用 serializerFactory 根據類來獲得 serializer 序列化工具類
public void writeObject(Object object)
throws IOException?
{?
if (object == null) {?
writeNull();?
return;?
}?
?
Serializer serializer;?
?
serializer = _serializerFactory.getSerializer(object.getClass()); ?
?
serializer.writeObject(object, this);?
}?
其 writeObject 是必須在子類實現的方法, AbstractSerializer 有 17 種子類實現, hessian 根據不同的 java 對象類型來實現了不同的序列化工具類,其中默認的是 JavaSerializer 。
而 JavaSerializer 的 writeObject 方法的實現,遍歷 java 對象的數據成員,根據數據成員的類型來獲得各自的 FieldSerializer ,一共有 6 中默認的 FieldSerializer 。
拿默認的 FieldSerializer 舉例,還是調用 AbstractHessianOutput 的子類來 writeObject ,這個時候,肯定能找到相應的 Serializer 來做序列化
?
同理可以反推出 hessian 的反序列化機制。 SerializerFactory 可以根據需要被反序列化的類來獲得反序列化工具類來做反序列化操作。
?
總結:得益于 hessian 序列號和反序列化的實現機制, hessian 序列化的速度很快,而且序列化后的字節數也較其他技術少。
?
總結
以上是生活随笔為你收集整理的Hessian 原理分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SAP--DEBUG--外部断点的设置
- 下一篇: response code 404 50