Hessian使用
ps:以前在项目中用过hessian,但我仅停留在知道这个层面,后面也没有详细了解其中的原理。现在要写简历都不知道怎么写,自己挖的坑,跪着也要填平。
Hessian的使用
这里先写下工程中的使用,有个直观的感觉。
maven配置
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.37</version>
</dependency>
sevice中配置:spring-hessian-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <bean name="/sysParamService" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="sysParamService" />
<property name="serviceInterface" value="cn.szfesc.rdp.opss.common.system.sysparam.service.SysParamService" />
</bean> <!-- 用户管理Service -->
<bean name="/sysUserService" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="sysUserService" />
<property name="serviceInterface" value="cn.szfesc.rdp.opss.common.system.user.service.SysUserService" />
</bean> <!-- 菜单管理 -->
<bean name="/sysMenuService" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="sysMenuService" />
<property name="serviceInterface" value="cn.szfesc.rdp.opss.common.system.menu.service.SysMenuService" />
</bean> <!-- 角色操作资源管理 -->
<bean name="/sysOperationService" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="sysOperationService" />
<property name="serviceInterface" value="cn.szfesc.rdp.opss.common.system.operation.service.SysOperationService" />
</bean> ... </beans>
其中的service属性在工程中通过注解@sevicce在实现类中定义bean,serviceInterface则表示实现类的接口。
web中配置:spring-remote.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rdp="http://com.szfesc.rdp.core/schema/rdp"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://com.szfesc.rdp.core/schema/rdp http://com.szfesc.rdp.core/schema/rdp/rdp.xsd"> <!-- 系统参数 -->
<bean id="sysParamService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="${serviceUrl}/sysParamService" />
<property name="serviceInterface" value="cn.szfesc.rdp.opss.common.system.sysparam.service.SysParamService" />
</bean> <!-- 用户管理 -->
<bean id="sysUserService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="${serviceUrl}/sysUserService" />
<property name="serviceInterface" value="cn.szfesc.rdp.opss.common.system.user.service.SysUserService" />
</bean> <!-- 菜单管理 -->
<bean id="sysMenuService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="overloadEnabled" value="true" />
<property name="serviceUrl" value="${serviceUrl}/sysMenuService" />
<property name="serviceInterface" value="cn.szfesc.rdp.opss.common.system.menu.service.SysMenuService" />
</bean> <!-- 角色操作资源管理 -->
<bean id="sysOperationService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="${serviceUrl}/sysOperationService" />
<property name="serviceInterface" value="cn.szfesc.rdp.opss.common.system.operation.service.SysOperationService" />
</bean>
...
</beans>
其中的serviceUrl在application.properties配置。
在web中调用service中的方法,就像是在本地中调用一样,达到了应用和服务相分离的目的。
Hessian 原理分析
一. 远程通讯协议的基本原理
网络通信需要做的就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络 IO 来实现,
其中传输协议比较出名的有 http 、 tcp 、 udp 等等, http 、 tcp 、 udp 都是在基于 Socket 概念上为某类应用场景而扩展出的传输协议,
网络 IO ,主要有 bio 、 nio 、 aio 三种方式,所有的分布式应用通讯都基于这个原理而实现,只是为了应用的易用,各种语言通常都会提供一些更为贴近应用易用的应用层协议。
二. 应用级协议 Binary-RPC
RPC(Remote Procedure Call)远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易
RMI:远程方法调用(Remote Method Invocation)。能够让在某个java虚拟机上的对象像调用本地对象一样调用另一个java 虚拟机中的对象上的方法。
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 方法体来填充所生成代理类的方法体。
ps:JDK动态代理,代理接口
客户端系统启动时:
根据 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;
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 实现序列化和反序列化的核心结构代码。
AbstractSerializerFactory ,它有 2 个抽象方法:
根据类来决定用哪种序列化工具类
abstract public Serializer getSerializer(Class cl) throws HessianProtocolException;
根据类来决定用哪种反序列化工具类
abstract public Deserializer getDeserializer(Class cl) throws HessianProtocolException;
SerializerFactory 继承 AbstractSerializerFactory 。
在 SerializerFactory 有很多静态 map 用来存放类与序列化和反序列化工具类的映射,这样如果已经用过的序列化工具就可以直接拿出来用,不必再重新实例化工具类。
在 SerializerFactory 中,实现了抽象类的 getSerializer 方法,根据不同的需要被序列化的类来获得不同的序列化工具,一共有 17 种序列化工具, 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 = _serializerFactory.getSerializer(object.getClass());
serializer.writeObject(object, this);
}
现在我们来看看 AbstractSerializer 。
其 writeObject 是必须在子类实现的方法, AbstractSerializer 有 17 种子类实现, hessian 根据不同的 java 对象类型来实现了不同的序列化工具类,其中默认的是 JavaSerializer 。
而 JavaSerializer 的 writeObject 方法的实现,遍历 java 对象的数据成员,根据数据成员的类型来获得各自的 FieldSerializer ,一共有 6 中默认的 FieldSerializer 。
拿默认的 FieldSerializer 举例,还是调用 AbstractHessianOutput 的子类来 writeObject ,这个时候,肯定能找到相应的 Serializer 来做序列化
同理可以反推出 hessian 的反序列化机制。 SerializerFactory 可以根据需要被反序列化的类来获得反序列化工具类来做反序列化操作。
总结:得益于 hessian 序列号和反序列化的实现机制, hessian 序列化的速度很快,而且序列化后的字节数也较其他技术少。
Hessian使用的更多相关文章
- spring remoting源码分析--Hessian分析
1. Caucho 1.1 概况 spring-remoting代码的情况如下: 本节近分析caucho模块. 1.2 分类 其中以hession为例,Hessian远程服务调用过程: Hessian ...
- spring与hessian整合例
spring与hessian的简单应用实现例: 开发环境:window7 64,jdk8,tomcat8,spring4.2.5,hessian4.0 开发语言:java hessianServer端 ...
- 十五分钟学会用Hessian
了解Hessian Hessian是远程调用的一种技术,和WebService类似,但不同的是较WebService而言,它更轻量级,更简单,更快速.关于Hessian更详细全面的介绍可以查看http ...
- Spring远程调用技术<2>-Hessian和Burlap
上篇谈到RMI技术,加上Spring的封装,用起来很方便,但也有一些限制 这里的Hessian和Burlap解决了上篇提到的限制,因为他们是基于http的轻量级远程服务. Hessian,和RMI一样 ...
- Xml,Json,Hessian,Protocol Buffers序列化对比
简介 这篇博客主要对Xml,Json,Hessian,Protocol Buffers的序列化和反序列化性能进行对比,Xml和Json的基本概念就不说了. Hessian:Hessian是一个轻量级的 ...
- java和c#使用hessian通信
介绍 hessian主页:http://hessian.caucho.com/ 一个简单的例子学习hessian服务:服务端为Java,客户端为C#. 先要准备好C#和Java的第三方类库:http: ...
- Hessian怎样实现远程调用
1.Spring中除了提供HTTP调用器方式的远程调用,还对第三方的远程调用实现提供了支持,其中提供了对Hessian的支持. Hessian是由Caocho公司发布的一个轻量级的二进制协议远程调用实 ...
- com.caucho.hessian.io.HessianProtocolException: is unknown code 解决方案
问题: Cannot access Hessian remote service at [http://....../remote/syllabusService]; nested exception ...
- Hessian最佳实践
前言:本文主要介绍‘独立的Hessian技术’与‘结合Spring技术’的两种Hessian接口开发模式及代码示例. 一.独立的Hessian技术开发步骤 Hessian-Java服务器端必须具备以下 ...
- RPC hessian简单案例
RPC(Remote procedure call) 远程服务调用. dubbox就是RPC框架,hessian是简单的RPC实现. 首先需要有接口及其实现类: 接口. public interfac ...
随机推荐
- Steamworks上传游戏
1.在steamPipe下配置Depot,每个Depot表示程序对应的分支配置语言,操作系统,架构组合等 2.安装,启动项目是配置游戏启动文件的相关信息,不同的操作系统架构等需要添加不同的启动项 3. ...
- Codeforces Round #505 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)-C. Plasticine zebra
问了学长,感觉还是很迷啊,不过懂了个大概,这个翻转操作,实质不就是在序列后面加上前面部分比如 bw | wwbwwbw 操作过后 wbwbwwbww 而 bw | wwbwwbwbw 这样我们就知道 ...
- linux内核分析第八次实验
20135118 罗鹏越 本周学习的是linux内核中的进程调度,之前我们在操作系统中有讲解进程调度的分类,以及一些调度算法.而linux中的进程调度有所不同,首先老师讲解了进程调度和进程调度的时机, ...
- linux及安全第五周总结
给MenuOS增加time和time-asm命令 中间过程已省略了,我们所做的只是将menu更新 具体命令如下 rm menu -rf 强制删除 git clone http://github.com ...
- UserControl 的一个值得注意的问题 [属性" * "的代码生成失败.错误是:"程序集"*.Version=1.0.0.0,Culture=neutral,..........无标记为序列化"
开发时在做UserControl,需要注意的List<>集合问题~~~! 其他类型的集合可能也存在这样的问题,但是我没去测试,在写集合的时候一般List<>用的多点,所以经常碰 ...
- 实验十一 团队作业7—团队项目设计完善&编码测试
实验十一 团队作业7—团队项目设计完善&编码测试 实验时间 2018-6-8 Deadline: 2018-6-20 10:00,以团队随笔博文提交至班级博客的时间为准. 评分标准: 按时交 ...
- PHP使用cookie时遇到的坑
先看这么一段代码 第一次运行该程序的结果如下图: 然后我刷新了一次,运行结果如下图 你如果不细心,一定没发现,第二次运行的last time的值,正是第一次运行时保存的值. 先看代码,如果$_COOK ...
- [转帖]一文看懂web服务器、应用服务器、web容器、反向代理服务器区别与联系
一文看懂web服务器.应用服务器.web容器.反向代理服务器区别与联系 https://www.cnblogs.com/vipyoumay/p/7455431.html 我们知道,不同肤色的人外貌差别 ...
- const修饰符与函数
一.用const修饰函数的参数 函数参数类型前加const指明该参数为常量,在函数内部不可改变. void func(const int x) { //x不可以在内部进行赋值等操作. } 注:当参数为 ...
- Linux 重启网络提示找不到eth0(no device found for “System eth0”)
一.背景 使用VMWare创建了一个虚拟机(VM1),然后通过拷贝的方式创建了另一台虚拟机(VM2).在第二台虚拟机上设置网卡为固定IP,使用service network restart重启网络的时 ...