1. 程式人生 > >遠端通訊框架-Hessian

遠端通訊框架-Hessian

一、什麼是hessian

        hessian 是一個基於binary-RPC 實現的遠端通訊library。

     使用二進位制傳輸資料。

     hessian 通常通過Web應用來提供服務,通過介面暴露。

     Servlet 和 Spring的DispatcherServlet都可以把請求轉發給Hessian服務。

     由以下兩種方式提供:

             com.caucho.hessian.server.HessianServlet。

             org.springframework.web.servlet.DispatcherServlet。

     關於hessian的問題:

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

               基於Binary-RPC協議實現的。

              2、怎麼發起請求?

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

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

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

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

                 hessian基於Http協議進行傳輸。

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

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

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

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

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

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

二、Hessian的優缺點

       缺點:

           缺乏安全機制,傳輸沒有加密

           異常機制不完善,總是報一些錯誤,錯誤原因也是很多,提示資訊不足。

           事務處理欠缺

           版本問題,(我自己在專案中使用的是hessian-3.1.3.jar)

       優點:

           簡單易用,面向介面,通過介面暴露服務,不需要配置防火牆效率高,複雜物件序列化速度僅次於RMI,簡單物件序列化優於RMI,二進位制傳輸多語言支援:wiki、java、Flash/Flex、Python、C++、.NET C# 、PHP等

           可與Spring整合,配置簡單

三、各個通訊協議對比:            通訊效率測試結果:                RMI > Httpinvoker >= Hessian >> Burlap >> Web service           1.RMI 是 Java 首選遠端呼叫協議,非常高效穩定,特別是在資料結構複雜,資料量大的情況下,與其他通訊協議的差距尤為明顯。但不能跨語言。           2.HttpInvoker 使用 java 的序列化技術傳輸物件,與 RMI 在本質上是一致的。從效率上看,兩者也相差無幾, HttpInvoker 與 RMI 的傳輸時間基本持平。           3.Hessian 在傳輸少量物件時,比 RMI 還要快速高效,但傳輸資料結構複雜的物件或大量資料物件時,較 RMI 要慢 20% 左右。但這只是在資料量特別大, 資料結構很複雜的情況下才能體現出來,中等或少量資料時, Hessian並不比RMI慢。 Hessian 的好處是精簡高效,可以跨語言使用,而且協議規範公開, 我們可以針對任意語言開發對其協議的實現。另外, Hessian與WEB伺服器結合非常好,藉助WEB伺服器的成熟功能,在處理大量使用者併發訪問時會有很大優勢,在資源分配, 執行緒排隊,異常處理等方面都可以由成熟的WEB伺服器保證。而 RMI 本身並不提供多執行緒的伺服器。而且,RMI 需要開防火牆埠, Hessian 不用。          4.Burlap 採用 xml 格式傳輸。僅在傳輸 1 條資料時速度尚可,通常情況下,它的毫時是 RMI 的 3 倍。          5.Web Service 的效率低下是眾所周知的,平均來看, Web Service 的通訊毫時是 RMI 的 10 倍。 四、基本流程
         客戶端必須具備以下幾點:   ·java客戶端包含Hessian.jar的包。   ·具有和伺服器端結構一樣的介面。 ·          利用HessianProxyFactory呼叫遠端介面。 ·           使用spring方式需要配置HessianProxyFactoryBean        JAVA伺服器端必須具備以下幾點:   ·包含Hessian的jar包。   ·設計一個介面,用來給客戶端呼叫。   ·實現該介面的功能。   ·配置web.xml,配好相應的servlet。   ·物件必須實現Serializable 介面。   ·對於spring方式DispatcherServlet攔截url,HessianServiceExporter提供Bean服務 五、原始碼分析 1.     客戶端發起請求 使用動態代理來實現的。除去 spring 對其的封裝,客戶端主要是通過 HessianProxyFactory 的 create 方法就是建立介面的代理類,該類實現了介面,  JDK 的 proxy 類會自動用 InvocationHandler 的實現類(該類在 Hessian 中表現為 HessianProxy )的 invoke 方法體來填充所生成代理類的方法體 1、客戶端呼叫 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();    // 發出請求

         // 等待伺服器端返回相應…………

                  InputStream is = conn.getInputStream();
                  AbstractHessianInput in = _factory.getHessianInput(is); //轉化為hessian自己的輸入輸出API
                  Object value = in.readObject(method.getReturnType()); // 取得返回值
}

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.     伺服器端接收請求並處理請求

伺服器端截獲相應請求交給:(Hessian2SkeletonInvoker) this.skeletonInvoker.invoke(inputStream, outputStream); 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();  
        out = new Hessian2Output(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在Spring中的工作流程如下:
(1)客戶端:
a.傳送遠端請求:
客戶端程式-->呼叫公共介面的方法-->Hessian攔截器攔截請求-->封裝遠端呼叫請求-->Hessian代理-->通過HTTP協議傳送遠端請求代理到服務端
b.接收遠端呼叫響應:
遠端呼叫結果-->HTTP響應-->客戶端
(2)服務端:
a.接收遠端呼叫請求:
HessianServiceExporter接收請求-->將遠端呼叫物件封裝為HessianSkeleton框架-->
HessianSkeleton處理遠端呼叫請求
b.返回遠端呼叫響應:
HessianSkeleton封裝遠端呼叫處理結果-->HTTP響應-->客戶端
下圖是通過hessian一次完成呼叫的示意圖

下面的程式碼是我自己在專案中用到的,大家可以參考,有更好的方法可以留言

SpringMVC 整合 Hessian

1、引用hessian-3.1.3.jar 

2、新建一個hessian-servlet.xml

3、在web.xml 裡面新增

       <!-- Spring 請求分發控制器 -->
       <servlet>
       <servlet-name>dispatcher</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <init-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>
         classpath*:dispatcher-config.xml
       </param-value>
       </init-param>
       <load-on-startup>0</load-on-startup>
       </servlet>

4、在dispatcher-config.xml 裡面新增配置資訊

      這個檔案裡面根據你們自己的專案配置一些相關資訊

      下面是我根據整合hessian加入的配置資訊

     <mvc:annotation-driven />(一開始我自己沒有加入spring自動的攔截器配置在測試的時候老是出現錯誤問題)

     <!-- Action 對映地址 -->
     <import resource="dispatcher-action.xml"/>

     <import resource="hessian-servlet.xml"/>

5、hessian-servlet.xml 中的配置

<!-- 業務類 -->
 <bean id="pointPayServiceImpl" class="com.point.web.service.PointPayServiceImpl"/>
 
 <!-- 遠端服務 -->
 <bean name="hessianService" class="org.springframework.remoting.caucho.HessianServiceExporter">
  <property name="service" ref="pointPayServiceImpl"/>
  <property name="serviceInterface">
   <value>
    com.point.web.service.IPointPayService
   </value>
  </property>
 </bean>

6、dispatcher-action.xml 配置

   <!-- 配置url的mapping對映 -->
 <bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
   <props>
     <prop key="/hessian/alipay">hessianService</prop>
   </props>
  </property>
 </bean>

上面內容相當於Server端

客戶端:

   1、引用hessian-3.1.3.jar 

    2、在方法裡面寫

       String payurl = "http://xxx:8080/demo/hessian/alipay";
  HessianProxyFactory factory = new HessianProxyFactory();
  //factory.setOverloadEnabled(true);
  ITestService hessianService =( ITestService)factory.create( ITestService.class,payurl);
  String message = hessianService.requestAlipay(param);

如果把客戶端變成服務端配置

web.xml:

   <servlet>
    <servlet-name>DemoHessian</servlet-name>
    <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
    <init-param>
      <param-name>home-class</param-name>
      <param-value>com.point.web.service.PointPayServiceImpl</param-value>
    </init-param>
    <init-param>
      <param-name>home-api</param-name>
      <param-value>com.point.web.service.IPointPayService</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>DemoHessian</servlet-name>
    <url-pattern>/hessianService</url-pattern>
  </servlet-mapping>

需要注意的是:客戶端和服務端   介面、實現類和POJO的路徑必須一樣