了解Hessian
Hessian 是是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。使用二进制传输数据。
Hessian通常通过Web应用来提供服务,通过接口暴露。
Servlet和Spring的DispatcherServlet都可以把请求转发给Hessian服务。
由以下两种方式提供,分别为:
com.caucho.hessian.server.HessianServlet、org.springframework.web.servlet.DispatcherServlet。
框架模型
Hessian框架比较简单,其主要结构分为客户端和服务端,中间是基于http传输的。客户端主要做的事情就是把对远程接口调用序列化为流,并传输到服务端;服务端主要做的事情就是把传输过来的流反序列化为对服务的请求,调用相应服务后会把结果序列化为流返回给客户端,完整的调用过程如下图:
HessianProxy是hessian client处理客户端请求的核心类,它采用proxy的设计模式,代理客户端对远程接口的调用,hessian client的主流程的时序图如下所示:
HessianSkeleton是hessian server端的核心类,从输入流中返序列化出客户端调用的方法和参数,对服务端服务进行调用,然后把处理结果返回给客户端,主要流程时序图如下所示:
实现原理
1.Hessian 的序列化和反序列化实现
Hessian是基于binary-RPC 实现的远程通讯,在通讯是二进制流进行传输的,所以要对其进行序列化和反序列化。AbstractSerializerFactory , AbstractHessianOutput , AbstractSerializer , AbstractHessianInput , AbstractDeserializer 是 hessian 实现序列化和反序列化的核心结构代码。
//AbstractSerializerFactory 核心类
public abstract Serializer getSerializer(Class var1) throws HessianProtocolException;
public abstract Deserializer getDeserializer(Class var1) throws HessianProtocolException;
在 SerializerFactory 有很多静态 map 用来存放类与序列化和反序列化工具类的映射,这样如果已经用过的序列化工具就可以直接拿出来用,不必再重新实例化工具类。
在 SerializerFactory 中,实现了抽象类的 getSerializer 方法和 getDeserializer 方法,根据不同的需要被(反)序列化的类来获得不同的(反)序列化工具, hessian 为不同的类型的 java 对象实现了不同的(反)序列化工具,默认的(反)序列化工具是 JavaSerializer /JavaDeserializer 。
在序列化和反序列化时会先调用 serializerFactory 根据类来获得 serializer (反)序列化工具类
public Serializer getSerializer(Class cl) throws HessianProtocolException {
Serializer serializer;
if (this._cachedSerializerMap != null) {
serializer = (Serializer)this._cachedSerializerMap.get(cl);
if (serializer != null) {
return serializer;
}
}
serializer = this.loadSerializer(cl);
if (this._cachedSerializerMap == null) {
this._cachedSerializerMap = new ConcurrentHashMap(8);
}
this._cachedSerializerMap.put(cl, serializer);
return serializer;
}
2.客户端实现
客户端主要是通过 HessianProxyFactory 的 create 方法就是创建接口的代理类,该类实现了接口, JDK 的 proxy 类会自动用 InvocationHandler 的实现类(该类在 Hessian 中表现为 HessianProxy )的 invoke 方法体来填充所生成代理类的方法体。
HessianProxyFacotry对象,构造方法中创建了一个HessianProxyResolver对象,这个对象的lookup方法将用来查找远程服务,实际上还是rmi。
//HessianProxyResolver.class
public Object lookup(String type, String url) throws IOException {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
Class api = Class.forName(type, false, loader);
return this._factory.create(api, url);
} catch (Exception var5) {
throw new IOException(String.valueOf(var5));
}
}
//HessianProxyFactory .class的create方法
public Object create(Class<?> api, URL url, ClassLoader loader) {
if (api == null) {
throw new NullPointerException("api must not be null for HessianProxyFactory.create()");
} else {
InvocationHandler handler = null;
handler = new HessianProxy(url, this, api);
return Proxy.newProxyInstance(loader, new Class[]{api, HessianRemoteObject.class}, handler);
}
}
所以我们调用客户端很简单
HessianProxyFactory factory = new HessianProxyFactory();
IHelloService helloService = (IHelloService) factory.create(IHelloService.class, url);
String ret = helloService.sayHello("test");
System.out.println(ret);
3.服务端实现
服务接口定义,然后具体实现下就可以了
public interface IHelloService {
public String sayHello(String name);
}
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
System.out.println("sayHello方法被调用了");
return "hello " + name;
}
}
在web.xml里配置就行了,配置完成之后,启动项目,在地址栏输入:http://localhost:端口号/项目名/ServiceServlet
<servlet>
11 <!-- 配置 HessianServlet,Servlet的名字随便配置,例如这里配置成ServiceServlet-->
12 <servlet-name>ServiceServlet</servlet-name>
13 <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
14
15 <!-- 配置接口的具体实现类 -->
16 <init-param>
17 <param-name>service-class</param-name>
18 <param-value>com.hessian.service.impl.HelloServiceImpl</param-value>
19 </init-param>
20 </servlet>
21 <!-- 映射 HessianServlet的访问URL地址-->
22 <servlet-mapping>
23 <servlet-name>ServiceServlet</servlet-name>
24 <url-pattern>/ServiceServlet</url-pattern>
25 </servlet-mapping>
优缺点
优点:采用的是二进制RPC协议(Binary),具有轻量、传输量小、平台无关的特点,特别适合于目前网络带宽比较小的手机网络应用项目。简单易用,面向接口,通过接口暴露服务,jar包只有200、300k,效率高,复杂对象序列化速度仅次于RMI,简单对象序列化优于RMI,二进制传输多语言支持。可与spring集成,配置简单,使用HessianServiceExporter提供bean服务
缺点:传输的对象是复杂对象效率比RMI低。由于是把对象序列化为二进制流的形式在http信道中传输,那么对于安全性高的应用不应该采用hessian(比如网上支付等)。缺乏安全机制,传输没有加密处理, 异常机制不完善,总是报一些错误,错误原因也是千奇百怪,提示信息不足, 事务处理欠缺。