Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。
在进行基于Hessian的项目开发时,应当注意以下几点:
JAVA服务器端必须具备以下几点:
java客户端包含
原文网址: https://blog.csdn.net/zhtang0526/article/details/4788879
网络通信需要做的就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络 IO 来实现,其中传输协议比较出名的有 http 、 tcp 、 udp 等等, http 、 tcp 、 udp 都是在基于 Socket 概念上为某类应用场景而扩展出的传输协议,网络 IO ,主要有 bio 、 nio 、 aio 三种方式,所有的分布式应用通讯都基于这个原理而实现,只是为了应用的易用,各种语言通常都会提供一些更为贴近应用易用的应用层协议。
Binary-RPC是一种和RMI类似的远程调用的协议,它和RMI的不同之处在于它以标准的二进制格式来定义请求的信息(请求的对象、方法、参数等),这样的好处是什么呢,就是在跨语言通讯的时候也可以使用。
来看下Binary -RPC协议的一次远程通信过程:
1、客户端发起请求,按照Binary -RPC协议将请求信息进行填充;
2、填充完毕后将二进制格式文件转化为流,通过传输协议进行传输;
3、接收到在接收到流后转换为二进制格式文件,按照Binary -RPC协议获取请求的信息并进行处理;
4、处理完毕后将结果按照Binary -RPC协议写入二进制格式文件中并返回。
问题总结:
1 、传输的标准格式是?
标准格式的二进制文件。
2 、怎么样将请求转化为传输的流?
将二进制格式文件转化为流。
3 、怎么接收和处理流?
通过监听的端口获取到请求的流,转化为二进制文件,根据协议获取请求的信息,进行处理并将结果写入 XML 中返回。
4 、传输协议是?
Http 【http协议底层是包装tcp协议】
Hessian 是由 caucho 提供的一个基于 binary-RPC 实现的远程通讯 library 。
1 、是基于什么协议实现的?
基于 Binary-RPC 协议实现。
2 、怎么发起请求?
需通过 Hessian 本身提供的 API 来发起请求。
3 、怎么将请求转化为符合协议的格式的?
Hessian 通过其自定义的串行化机制将请求信息进行序列化,产生二进制流。
4 、使用什么传输协议传输?
Hessian 基于 Http (底层tcp)协议进行传输。
5 、响应端基于什么机制来接收请求?
响应端根据 Hessian 提供的 API 来接收请求。
6 、怎么将流还原为传输格式的?
Hessian 根据其私有的串行化机制来将请求信息进行反序列化,传递给使用者时已是相应的请求信息对象了。
7 、处理完毕后怎么回应?
处理完毕后直接返回, 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 = 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;
服务器端截获相应请求交给:
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源码中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序列化的速度很快,而且序列化后的字节数也较其他技术少。
1.调用客户端句柄;执行传送参数
2.调用本地系统内核发送网络消息
3.消息传送到远程主机
4.服务器句柄得到消息并取得参数
5.执行远程过程
6.执行的过程将结果返回服务器句柄
7.服务器句柄返回结果,调用远程系统内核
8.消息传回本地主机
9.客户句柄由内核接收消息
10.客户接收句柄返回的数据