1. 程式人生 > >【hessian】一 hessian 基本介紹

【hessian】一 hessian 基本介紹

Hessian介紹

Hessian是一個輕量級的remoting onhttp工具,使用簡單的方法提供了RMI的功能. 相比WebService,Hessian更簡單、快捷。採用的是二進位制RPC協議,因為採用的是二進位制協議,所以它很適合於傳送二進位制資料。

這裡寫圖片描述

在進行基於Hessian的專案開發時,應當注意以下幾點:

JAVA伺服器端必須具備以下幾點:

  1. 包含Hessian的jar包
  2. 設計一個介面,用來給客戶端呼叫
  3. 實現該介面的功能
  4. 配置web.xml,配好相應的servlet
  5. 物件必須實現Serializable 介面
  6. 對於複雜對像可以使用Map的方法傳遞

java客戶端包含

  1. Hessian.jar的包
  2. ·具有和伺服器端結構一樣的介面。包括名稱空間都最好一樣
  3. 利用HessianProxyFactory呼叫遠端介面。

Hessian原理分析

原文網址: https://blog.csdn.net/zhtang0526/article/details/4788879

一. 遠端通訊協議的基本原理

網路通訊需要做的就是將流從一臺計算機傳輸到另外一臺計算機,基於傳輸協議和網路 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 【http協議底層是包裝tcp協議】

三. Hessian 是一種實現遠端通訊的 library

Hessian 是由 caucho 提供的一個基於 binary-RPC 實現的遠端通訊 library 。

1 、是基於什麼協議實現的?

基於 Binary-RPC 協議實現。

2 、怎麼發起請求?

需通過 Hessian 本身提供的 API 來發起請求。

3 、怎麼將請求轉化為符合協議的格式的?

Hessian 通過其自定義的序列化機制將請求資訊進行序列化,產生二進位制流。

4 、使用什麼傳輸協議傳輸?

Hessian 基於 Http (底層tcp)協議進行傳輸。

5 、響應端基於什麼機制來接收請求?

響應端根據 Hessian 提供的 API 來接收請求。

6 、怎麼將流還原為傳輸格式的?

Hessian 根據其私有的序列化機制來將請求資訊進行反序列化,傳遞給使用者時已是相應的請求資訊物件了。

7 、處理完畢後怎麼迴應?

處理完畢後直接返回, hessian 將結果物件進行序列化,傳輸至呼叫端。

四. Hessian原始碼分析

以hessian和spring dm server整合環境為例。

1. 客戶端發起請求

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;

2. 伺服器端接收請求並處理請求

伺服器端截獲相應請求交給:
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實現序列化和反序列化的核心結構程式碼。

1. AbstractSerializerFactory,它有2個抽象方法:
根據類來決定用哪種序列化工具類
abstract public Serializer getSerializer(Class cl) throws HessianProtocolException;
根據類來決定用哪種反序列化工具類
abstract public Deserializer getDeserializer(Class cl) throws HessianProtocolException;
2. SerializerFactory繼承AbstractSerializerFactory。
在SerializerFactory有很多靜態map用來存放類與序列化和反序列化工具類的對映,這樣如果已經用過的序列化工具就可以直接拿出來用,不必再重新例項化工具類。
在SerializerFactory中,實現了抽象類的getSerializer方法,根據不同的需要被序列化的類來獲得不同的序列化工具,一共有 17種序列化工具,hessian為不同的型別的java物件實現了不同的序列化工具,預設的序列化工具是JavaSerializer。
在SerializerFactory中,也實現了抽象類的getDeserializer方法,根據不同的需要被反序列化的類來獲得不同的反序列化工具,預設的反序列化工具類是JavaDeserializer。
3. HessianOutput繼承AbstractHessianOutput成為序列化輸出流的一種實現。
它會實現很多方法,用來做流輸出。
需要注意的是方法,它會先呼叫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);
}
4. 現在我們來看看AbstractSerializer。
其writeObject是必須在子類實現的方法,AbstractSerializer有17 種子類實現,hessian根據不同的java物件型別來實現了不同的序列化工具類,其中預設的是JavaSerializer。
而JavaSerializer的writeObject方法的實現,遍歷java物件的資料成員,根據資料成員的型別來獲得各自的FieldSerializer,一共有6中預設的FieldSerializer。
拿預設的FieldSerializer舉例,還是呼叫AbstractHessianOutput的子類來writeObject,這個時候,肯定能找到相應的Serializer來做序列化
同理可以反推出hessian的反序列化機制。SerializerFactory可以根據需要被反序列化的類來獲得反序列化工具類來做反序列化操作。

總結:得益於hessian序列號和反序列化的實現機制,hessian序列化的速度很快,而且序列化後的位元組數也較其他技術少。

六、hessian的RPC呼叫10個步驟(客戶端呼叫服務端)

如圖:
這裡寫圖片描述

1.呼叫客戶端控制代碼;執行傳送引數
2.呼叫本地系統核心傳送網路訊息
3.訊息傳送到遠端主機
4.伺服器控制代碼得到訊息並取得引數
5.執行遠端過程
6.執行的過程將結果返回伺服器控制代碼
7.伺服器控制代碼返回結果,呼叫遠端系統核心
8.訊息傳回本地主機
9.客戶控制代碼由核心接收訊息
10.客戶接收控制代碼返回的資料