电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

Hessian 原理分析


发布日期:2018/9/6
 

一. 远程通讯协议的基本原理

网络通信需要做的就是将流从一台计算机传输到另外一台计算机基于传输协议和网络 IO 来实现其中传输协议比较出名的有 http tcp udp 等等 http tcp udp 都是在基于 Socket 概念上为某类应用场景而扩展出的传输协议网络 IO 主要有 bio nio aio 三种方式所有的分布式应用通讯都基于这个原理而实现只是为了应用的易用各种语言通常都会提供一些更为贴近应用易用的应用层协议

二.应用级协议 BinaryRPC

BinaryRPC 是一种和 RMI 类似的远程调用的协议它和 RMI 的不同之处在于它以标准的二进制格式来定义请求的信息 ( 请求的对象方法参数等 ) 这样的好处是什么呢就是在跨语言通讯的时候也可以使用

来看下 Binary RPC 协议的一次远程通信过程

客户端发起请求按照 Binary RPC 协议将请求信息进行填充;

填充完毕后将二进制格式文件转化为流通过传输协议进行传输;

接收到在接收到流后转换为二进制格式文件按照 Binary RPC 协议获取请求的信息并进行处理;

处理完毕后将结果按照 Binary RPC 协议写入二进制格式文件中并返回

问题总结

传输的标准格式是?

标准格式的二进制文件

怎么样将请求转化为传输的流?

将二进制格式文件转化为流

怎么接收和处理流?

通过监听的端口获取到请求的流转化为二进制文件根据协议获取请求的信息进行处理并将结果写入 XML 中返回

传输协议是?

Http

三. Hessian ——一种实现远程通讯的 library

Hessian 是由 caucho 提供的一个基于 binaryRPC 实现的远程通讯 library

是基于什么协议实现的?

基于 BinaryRPC 协议实现

怎么发起请求?

需通过 Hessian 本身提供的 API 来发起请求

怎么将请求转化为符合协议的格式的?

Hessian 通过其自定义的串行化机制将请求信息进行序列化产生二进制流

使用什么传输协议传输?

Hessian 基于 Http 协议进行传输

响应端基于什么机制来接收请求?

响应端根据 Hessian 提供的 API 来接收请求

怎么将流还原为传输格式的?

Hessian 根据其私有的串行化机制来将请求信息进行反序列化传递给使用者时已是相应的请求信息对象了

处理完毕后怎么回应?

处理完毕后直接返回 hessian 将结果对象进行序列化传输至调用端

四. Hessian 源码分析

以 hessian 和 spring dm server 整合环境为例

客户端发起请求

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 = methodgetName();// 取得方法名

Object value = args[]; // 取得传入参数

conn = sendRequest(mangleName args) ; // 通过该方法和服务器端取得连接

httpConn = (HttpURLConnection) conn;

code = (); // 发出请求

// 等待服务器端返回相应…………

is = conngetInputStream();

Object value = inreadObject(methodgetReturnType()); // 取得返回值

HessianProxy 类的 URLConnection sendRequest(String methodName Object []args) 方法

URLConnection conn = _factoryopenConnection(_url); // 创建 URLConnection

OutputStream os = conngetOutputStream();

AbstractHessianOutput out = _factorygetHessianOutput(os); // 封装为 hessian 自己的输入输出 API

outcall(methodName args);

return conn;

服务器端接收请求并处理请求

服务器端截获相应请求交给

orgspringframeworkremotingcauchoHessianServiceExporter

具体处理步骤如下

a) HessianServiceExporter 类

(HessianExporter) invoke(requestgetInputStream() responsegetOutputStream());

b) HessianExporter 类

(HessianSkeletonInvoker) thisskeletonInvokerinvoke(inputStream outputStream);

c) HessianSkeletonInvoker 类

将输入输出封转化为转化为 Hessian 特有的 HessianInput 和 HessianOutput

HessianInput in = new HessianInput(isToUse);

insetSerializerFactory(thisserializerFactory);

AbstractHessianOutput out = null;

int major = inread();

int minor = inread();

out = new HessianOutput(osToUse);

out = new HessianOutput(osToUse);

outsetSerializerFactory(thisserializerFactory);

(HessianSkeleton) thisskeletoninvoke(in out);

d) HessianSkeleton 类

读取方法名

String methodName = inreadMethod();

Method method = getMethod(methodName);

读取方法参数

Class []args = methodgetParameterTypes();

Object []values = new Object[argslength];

执行相应方法并取得结果

result = methodinvoke(service values);

结果写入到输出流

outwriteObject(result);

总结 由上面源码分析可知客户端发起请求和服务器端接收处理请求都是通过 hessian 自己的 API 输入输出流都要封装为 hessian 自己的 HessianInput 和 HessianOutput 接下来一节我们将去了解 hessian 自己封装的输入输出到底做了些什么!

五. Hessian 的序列化和反序列化实现

hessian 源码中 comcauchohessianio 这个包是 hessian 实现序列化与反序列化的核心包其中 AbstractSerializerFactory AbstractHessianOutput AbstractSerializer AbstractHessianInput AbstractDeserializer 是 hessian 实现序列化和反序列化的核心结构代码

AbstractSerializerFactory 它有 个抽象方法

根据类来决定用哪种序列化工具类

abstract public Serializer getSerializer(Class cl) throws HessianProtocolException;

根据类来决定用哪种反序列化工具类

abstract public Deserializer getDeserializer(Class cl) throws HessianProtocolException;

SerializerFactory 继承 AbstractSerializerFactory

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

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

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

HessianOutput 继承 AbstractHessianOutput 成为序列化输出流的一种实现

它会实现很多方法用来做流输出

需要注意的是方法它会先调用 serializerFactory 根据类来获得 serializer 序列化工具类

public void writeObject(Object object)

throws IOException

{

if (object == null) {

writeNull();

return;

}

Serializer serializer;

serializer = _serializerFactorygetSerializer(objectgetClass());

serializerwriteObject(object this);

}

现在我们来看看 AbstractSerializer

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

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

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

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

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

上一篇:GroupLayout布局管理器实例

下一篇:Swing 中的声音