远程通信框架-Hessian

来源:互联网 发布:淘宝客服中心组织架构 编辑:程序博客网 时间:2024/06/07 05:49

一、什么是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的路径必须一样

0 0