原文地址:http://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 。

三.      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. 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;

  1. 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;

  1. SerializerFactory 继承 AbstractSerializerFactory 。

在 SerializerFactory 有很多静态 map 用来存放类与序列化和反序列化工具类的映射,这样如果已经用过的序列化工具就可以直接拿出来用,不必再重新实例化工具类。

在 SerializerFactory 中,实现了抽象类的 getSerializer 方法,根据不同的需要被序列化的类来获得不同的序列化工具,一共有 17 种序列化工具, hessian 为不同的类型的 Java 对象实现了不同的序列化工具,默认的序列化工具是 JavaSerializer 。

在 SerializerFactory 中,也实现了抽象类的 getDeserializer 方法,根据不同的需要被反序列化的类来获得不同的反序列化工具,默认的反序列化工具类是 JavaDeserializer 。

  1. 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);

}

  1. 现在我们来看看 AbstractSerializer 。

其 writeObject 是必须在子类实现的方法, AbstractSerializer 有 17 种子类实现, hessian 根据不同的java 对象类型来实现了不同的序列化工具类,其中默认的是 JavaSerializer 。

而 JavaSerializer 的 writeObject 方法的实现,遍历 java 对象的数据成员,根据数据成员的类型来获得各自的 FieldSerializer ,一共有 6 中默认的 FieldSerializer 。

拿默认的 FieldSerializer 举例,还是调用 AbstractHessianOutput 的子类来 writeObject ,这个时候,肯定能找到相应的 Serializer 来做序列化

同理可以反推出 hessian 的反序列化机制。 SerializerFactory 可以根据需要被反序列化的类来获得反序列化工具类来做反序列化操作。

总结:得益于 hessian 序列号和反序列化的实现机制, hessian 序列化的速度很快,而且序列化后的字节数也较其他技术少。

参考文献:

  1. 《 Java 远程通讯可选技术及原理》 http://java.chinaitlab.com/base/740383.html
  2. 《 Hessian-3.2.0 源码》
  3. 《 hessian 序列化实现初探》 http://www.javaeye.com/topic/245238
  4. 《 Hessian 2.0 序列化协议规范》

http://blog.csdn.net/xpspace/archive/2007/10/05/1811603.aspx

Hessian 原理分析--转的更多相关文章

  1. Hessian 原理分析

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

  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. 人脸识别经典算法三:Fisherface(LDA)

    Fisherface是由Ronald Fisher发明的,想必这就是Fisherface名字由来.Fisherface所基于的LDA(Linear Discriminant Analysis,线性判别 ...

  2. proxyd.c

    /**************************************************************************** * program: proxyd * mo ...

  3. Entity FrameWork 单表对多实体

    一个影片信息Clips表,四个字段:clipId,clipName,fileSize,fileName 方案一: [Table("Clips")] public class Cli ...

  4. Twitter全局唯一ID生成算法

    测试:private static void TestIdWorker() { HashSet<long> set = new HashSet<long>(); IdWorke ...

  5. ORM查询语言(OQL)简介--高级篇(续):庐山真貌

    相关文章内容索引: ORM查询语言(OQL)简介--概念篇 ORM查询语言(OQL)简介--实例篇 ORM查询语言(OQL)简介--高级篇:脱胎换骨 ORM查询语言(OQL)简介--高级篇(续):庐山 ...

  6. [后端人员耍前端系列]KnockoutJs篇:使用WebApi+Bootstrap+KnockoutJs打造单页面程序

    一.前言 在前一个专题快速介绍了KnockoutJs相关知识点,也写了一些简单例子,希望通过这些例子大家可以快速入门KnockoutJs.为了让大家可以清楚地看到KnockoutJs在实际项目中的应用 ...

  7. Java语法糖4:内部类

    内部类 最后一个语法糖,讲讲内部类,内部类指的就是在一个类的内部再定义一个类. 内部类之所以也是语法糖,是因为它仅仅是一个编译时的概念,outer.java里面定义了一个内部类inner,一旦编译成功 ...

  8. 人人都是 DBA(XI)I/O 信息收集脚本汇编

    什么?有个 SQL 执行了 8 秒! 哪里出了问题?臣妾不知道啊,得找 DBA 啊. DBA 人呢?离职了!!擦!!! 程序员在无处寻求帮助时,就得想办法自救,努力让自己变成 "伪 DBA& ...

  9. Aoite 系列 目录

    介绍 本项目从2009年孵化(V->Sofire->Aoite),至今已度过5个年头.一直在优化,一直在重构,一直在商用.有十分完整的单元测试用例.可以放心使用. Aoite on 博客园 ...

  10. 记录排查解决Hubble.Net连接Oracle数据库建立镜像库数据丢失的问题

    起因 前几天在弄Hubble连接Oracle数据库,然后在mongodb中建立一个镜像数据库; 发现一个问题,原本数据是11W,但是镜像库中只有6w多条; 刚开始以为是没运行好,又rebuild了一下 ...