Hessian框架原理

了解Hessian

Hessian 是是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。使用二进制传输数据。
Hessian通常通过Web应用来提供服务,通过接口暴露。
Servlet和Spring的DispatcherServlet都可以把请求转发给Hessian服务。
由以下两种方式提供,分别为:
com.caucho.hessian.server.HessianServlet、org.springframework.web.servlet.DispatcherServlet。

框架模型

Hessian框架比较简单,其主要结构分为客户端和服务端,中间是基于http传输的。客户端主要做的事情就是把对远程接口调用序列化为流,并传输到服务端;服务端主要做的事情就是把传输过来的流反序列化为对服务的请求,调用相应服务后会把结果序列化为流返回给客户端,完整的调用过程如下图:

image.png

HessianProxy是hessian client处理客户端请求的核心类,它采用proxy的设计模式,代理客户端对远程接口的调用,hessian client的主流程的时序图如下所示:

image.png

HessianSkeleton是hessian server端的核心类,从输入流中返序列化出客户端调用的方法和参数,对服务端服务进行调用,然后把处理结果返回给客户端,主要流程时序图如下所示:

image.png

实现原理

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(比如网上支付等)。缺乏安全机制,传输没有加密处理, 异常机制不完善,总是报一些错误,错误原因也是千奇百怪,提示信息不足, 事务处理欠缺。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容