一. 遠程通訊協議的基本原理
網絡通信需要做的就是將流從一台計算機傳輸到另外一台計算機基於傳輸協議和網絡 IO 來實現其中傳輸協議比較出名的有 http tcp udp 等等 http tcp udp 都是在基於 Socket 概念上為某類應用場景而擴展出的傳輸協議網絡 IO 主要有 bio nio aio 三種方式所有的分布式應用通訊都基於這個原理而實現只是為了應用的易用各種語言通常都會提供一些更為貼近應用易用的應用層協議
二.應用級協議 BinaryRPC
BinaryRPC 是一種和 RMI 類似的遠程調用的協議它和 RMI 的不同之處在於它以標准的二進制格式來定義請求的信息 ( 請求的對象方法參數等 ) 這樣的好處是什麼呢就是在跨語言通訊的時候也可以使用
來看下 Binary RPC 協議的一次遠程通信過程
客戶端發起請求按照 Binary RPC 協議將請求信息進行填充;
填充完畢後將二進制格式文件轉化為流通過傳輸協議進行傳輸;
接收到在接收到流後轉換為二進制格式文件按照 Binary RPC 協議獲取請求的信息並進行處理;
處理完畢後將結果按照 Binary RPC 協議寫入二進制格式文件中並返回
問題總結
傳輸的標准格式是?
標准格式的二進制文件
怎麼樣將請求轉化為傳輸的流?
將二進制格式文件轉化為流
怎麼接收和處理流?
通過監聽的端口獲取到請求的流轉化為二進制文件根據協議獲取請求的信息進行處理並將結果寫入 XML 中返回
傳輸協議是?
Http
三. Hessian ——一種實現遠程通訊的 library
Hessian 是由 caucho 提供的一個基於 binaryRPC 實現的遠程通訊 library
是基於什麼協議實現的?
基於 BinaryRPC 協議實現
怎麼發起請求?
需通過 Hessian 本身提供的 API 來發起請求
怎麼將請求轉化為符合協議的格式的?
Hessian 通過其自定義的串行化機制將請求信息進行序列化產生二進制流
使用什麼傳輸協議傳輸?
Hessian 基於 Http 協議進行傳輸
響應端基於什麼機制來接收請求?
響應端根據 Hessian 提供的 API 來接收請求
怎麼將流還原為傳輸格式的?
Hessian 根據其私有的串行化機制來將請求信息進行反序列化傳遞給使用者時已是相應的請求信息對象了
處理完畢後怎麼回應?
處理完畢後直接返回 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 = methodgetName();// 取得方法名
Object value = args[]; // 取得傳入參數
conn = sendRequest(mangleName args) ; // 通過該方法和服務器端取得連接
httpConn = (HttpURLConnection) conn;
code = (); // 發出請求
// 等待服務器端返回相應…………
is = conngetInputStream();
Object value = inreadObject(methodgetReturnType()); // 取得返回值
HessianProxy 類的 URLConnection sendRequest(String methodName Object []args) 方法
URLConnection conn = _factoryopenConnection(_url); // 創建 URLConnection
OutputStream os = conngetOutputStream();
AbstractHessianOutput out = _factorygetHessianOutput(os); // 封裝為 hessian 自己的輸入輸出 API
outcall(methodName args);
return conn;
服務器端接收請求並處理請求
服務器端截獲相應請求交給
orgspringframeworkremotingcauchoHessianServiceExporter
具體處理步驟如下
a) HessianServiceExporter 類
(HessianExporter) invoke(requestgetInputStream() responsegetOutputStream());
b) HessianExporter 類
(HessianSkeletonInvoker) thisskeletonInvokerinvoke(inputStream outputStream);
c) HessianSkeletonInvoker 類
將輸入輸出封轉化為轉化為 Hessian 特有的 HessianInput 和 HessianOutput
HessianInput in = new HessianInput(isToUse);
insetSerializerFactory(thisserializerFactory);
AbstractHessianOutput out = null;
int major = inread();
int minor = inread();
out = new HessianOutput(osToUse);
out = new HessianOutput(osToUse);
outsetSerializerFactory(thisserializerFactory);
(HessianSkeleton) thisskeletoninvoke(in out);
d) HessianSkeleton 類
讀取方法名
String methodName = inreadMethod();
Method method = getMethod(methodName);
讀取方法參數
Class []args = methodgetParameterTypes();
Object []values = new Object[argslength];
執行相應方法並取得結果
result = methodinvoke(service values);
結果寫入到輸出流
outwriteObject(result);
總結 由上面源碼分析可知客戶端發起請求和服務器端接收處理請求都是通過 hessian 自己的 API 輸入輸出流都要封裝為 hessian 自己的 HessianInput 和 HessianOutput 接下來一節我們將去了解 hessian 自己封裝的輸入輸出到底做了些什麼!
五. Hessian 的序列化和反序列化實現
hessian 源碼中 comcauchohessianio 這個包是 hessian 實現序列化與反序列化的核心包其中 AbstractSerializerFactory AbstractHessianOutput AbstractSerializer AbstractHessianInput AbstractDeserializer 是 hessian 實現序列化和反序列化的核心結構代碼
AbstractSerializerFactory 它有 個抽象方法
根據類來決定用哪種序列化工具類
abstract public Serializer getSerializer(Class cl) throws HessianProtocolException;
根據類來決定用哪種反序列化工具類
abstract public Deserializer getDeserializer(Class cl) throws HessianProtocolException;
SerializerFactory 繼承 AbstractSerializerFactory
在 SerializerFactory 有很多靜態 map 用來存放類與序列化和反序列化工具類的映射這樣如果已經用過的序列化工具就可以直接拿出來用不必再重新實例化工具類
在 SerializerFactory 中實現了抽象類的 getSerializer 方法根據不同的需要被序列化的類來獲得不同的序列化工具一共有 種序列化工具 hessian 為不同的類型的 java 對象實現了不同的序列化工具默認的序列化工具是 JavaSerializer
在 SerializerFactory 中也實現了抽象類的 getDeserializer 方法根據不同的需要被反序列化的類來獲得不同的反序列化工具默認的反序列化工具類是 JavaDeserializer
HessianOutput 繼承 AbstractHessianOutput 成為序列化輸出流的一種實現
它會實現很多方法用來做流輸出
需要注意的是方法它會先調用 serializerFactory 根據類來獲得 serializer 序列化工具類
public void writeObject(Object object)
throws IOException
{
if (object == null) {
writeNull();
return;
}
Serializer serializer;
serializer = _serializerFactorygetSerializer(objectgetClass());
serializerwriteObject(object this);
}
現在我們來看看 AbstractSerializer
其 writeObject 是必須在子類實現的方法 AbstractSerializer 有 種子類實現 hessian 根據不同的 java 對象類型來實現了不同的序列化工具類其中默認的是 JavaSerializer
而 JavaSerializer 的 writeObject 方法的實現遍歷 java 對象的數據成員根據數據成員的類型來獲得各自的 FieldSerializer 一共有 中默認的 FieldSerializer
拿默認的 FieldSerializer 舉例還是調用 AbstractHessianOutput 的子類來 writeObject 這個時候肯定能找到相應的 Serializer 來做序列化
同理可以反推出 hessian 的反序列化機制 SerializerFactory 可以根據需要被反序列化的類來獲得反序列化工具類來做反序列化操作
總結得益於 hessian 序列號和反序列化的實現機制 hessian 序列化的速度很快而且序列化後的字節數也較其他技術少
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25997.html