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 整合环境为例。

1、客户端发起请求

Hessian 的这个远程过程调用,完全使用动态代理来实现的。有客户端可以看出。除去 spring 对其的封装,客户端主要是通过 HessianProxyFactory 的 create 方法就是创建接口的代理类,该类实现了接口, JDK 的 proxy 类会自动用 InvocationHandler 的实现类(该类在 Hessian 中表现为 HessianProxy )的 invoke 方法体来填充所生成代理类的方法体。

1.1 客户端系统启动时:

根据 serviceUrl 和 serviceInterface 创建代理。
         HessianProxyFactoryBean 类
         HessianClientInterceptor 类
                  createHessianProxy(HessianProxyFactory proxyFactory)
         HessianProxyFactory 类
                  public Object create(Class api, String urlName)

1.2 客户端调用 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 原理分析的更多相关文章

  1. Hessian 原理分析--转

    原文地址:http://blog.csdn.net/zhtang0526/article/details/4788879 一.      远程通讯协议的基本原理 网络通信需要做的就是将流从一台计算机传 ...

  2. Hessian原理分析

    一.      远程通讯协议的基本原理 网络通信需要做的就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络 IO 来实现,其中传输协议比较出名的有 http . tcp . udp 等等, ...

  3. Handler系列之原理分析

    上一节我们讲解了Handler的基本使用方法,也是平时大家用到的最多的使用方式.那么本节让我们来学习一下Handler的工作原理吧!!! 我们知道Android中我们只能在ui线程(主线程)更新ui信 ...

  4. Java NIO使用及原理分析(1-4)(转)

    转载的原文章也找不到!从以下博客中找到http://blog.csdn.net/wuxianglong/article/details/6604817 转载自:李会军•宁静致远 最近由于工作关系要做一 ...

  5. 原子类java.util.concurrent.atomic.*原理分析

    原子类java.util.concurrent.atomic.*原理分析 在并发编程下,原子操作类的应用可以说是无处不在的.为解决线程安全的读写提供了很大的便利. 原子类保证原子的两个关键的点就是:可 ...

  6. Android中Input型输入设备驱动原理分析(一)

    转自:http://blog.csdn.net/eilianlau/article/details/6969361 话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反 ...

  7. 转载:AbstractQueuedSynchronizer的介绍和原理分析

    简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过 ...

  8. Camel运行原理分析

    Camel运行原理分析 以一个简单的例子说明一下camel的运行原理,例子本身很简单,目的就是将一个目录下的文件搬运到另一个文件夹,处理器只是将文件(限于文本文件)的内容打印到控制台,首先代码如下: ...

  9. NOR Flash擦写和原理分析

    NOR Flash擦写和原理分析 1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直 ...

随机推荐

  1. 云服务器 ECS Linux 系统安装图形化桌面 (centos7 ubuntu14)

    基于性能及通用性等因素,默认情况下,阿里云官方公共 Linux 系统镜像不会安装图形化桌面组件.本文简述了常用操作系统图形化桌面安装说明,您可以根据需求进行配置系统. 注意:图形化桌面可能会 显著降低 ...

  2. versionCode溢出的问题

    android应用的版本主要由versionCode和versionName来决定,android系统是根据versionCode来验证新的apk是否能安装.如果已安装高版本的应用,就无法使用覆盖安装 ...

  3. 使用node-webkit实现打包工具的小结

    之前一直使用的hta在开发工具,最近转到node-webkit上了,对比一下二者的优劣势.hta单个文件,体积较小,但有兼容性的问题(兼容ie6.7.8就行了,也还好),node-webkit使用we ...

  4. An internal error occurred during: "Building workspace". GC overhead limit exceeded

    1 错误描写叙述 2 错误原因 3 解决的方法

  5. Java反编译工具Jad详解

    做项目过程中需要反编译一个jar包,于是作了一些学习,记录下来. Jad(JAva Decompiler)是一个Java的反编译器,可以通过命令行把Java的class文件反编译成源代码. 如果你在使 ...

  6. JavaScript:Functions

    ylbtech-JavaScript:Functions 1.返回顶部 JavaScript 全局对象 全局属性和函数可用于所有内建的 JavaScript 对象. 顶层函数(全局函数) 函数 描述 ...

  7. 混沌分形之迭代函数系统(IFS)

    IFS是分形的重要分支.它是分形图像处理中最富生命力而且最具有广阔应用前景的领域之一.这一工作最早可以追溯到Hutchinson于1981年对自相似集的研究.美国科学家M.F.Barnsley于198 ...

  8. C++11 std::shared_ptr总结与使用

    最近看代码,智能指针用的比较多,自己平时用的少,周末自己总结总结.方便后续使用. std::shared_ptr大概总结有以下几点: (1) 智能指针主要的用途就是方便资源的管理,自动释放没有指针引用 ...

  9. 计算机中的概念: 视图 VS 镜像

    这两个概念还是不太一样的.下面来说说个人的理解,记录一下. 1. 镜像 镜像可以理解为一份完全一样的拷贝.也就是"深度拷贝",一个复制品. 比如 iso映像文件,ubuntu-12 ...

  10. Go语言之高级篇beego框架之参数配置与路由配置

    一.参数配置 beego默认会解析当前应用下的conf/app.conf文件 1.1.beego的参数配置 appname = WEB httpport = 8080 runmode = dev 几种 ...