HessianSkeleton是Hessian的服务端的核心,简单总结来说:HessianSkeleton根据客户端请求的链接,获取到需要执行的接口及实现类,对客户端发送过来的二进制数据进行反序列化,获得需要执行的函数及参数值,然后根据函数和参数值执行具体的函数,接下来对执行的结果进行序列化然后通过连接返回给客户端。

接下来我们按照源码一步一步进行分析,在上一篇博客Hessian源码分析--HessianServlet我们了解到它是调用HessianSkeleton的invoke方法,接下来我们对invoke方法进行分析。

首先获取头类型,这个头类型应该是决定到底是使用那种序列化和反序列函数的,这里对序列化和反序列化不多过多分析。

然后接下来的操作就是调用invoke(_service, in, out)函数了,也没有其他重要的操作了。

public void invoke(InputStream is, OutputStream os,
                     SerializerFactory serializerFactory)
    throws Exception
  {
    HessianInputFactory.HeaderType header = _inputFactory.readHeader(is);

    AbstractHessianInput in;
    AbstractHessianOutput out;

    switch (header) {
    case CALL_1_REPLY_1:
      in = _hessianFactory.createHessianInput(is);
      out = _hessianFactory.createHessianOutput(os);
      break;

    case CALL_1_REPLY_2:
      in = _hessianFactory.createHessianInput(is);
      out = _hessianFactory.createHessian2Output(os);
      break;

    case HESSIAN_2:
      in = _hessianFactory.createHessian2Input(is);
      in.readCall();
      out = _hessianFactory.createHessian2Output(os);
      break;

    default:
      throw new IllegalStateException(header + " is an unknown Hessian call");
    }

    if (serializerFactory != null) {
      in.setSerializerFactory(serializerFactory);
      out.setSerializerFactory(serializerFactory);
    }

    try {
      invoke(_service, in, out);
    } finally {
      in.close();
      out.close();

      if (isDebug)
        os.close();
    }
  }

调用invoke(_service, in, out)函数实际是调用如下操作,也是没有具体操作

public void invoke(AbstractHessianInput in, AbstractHessianOutput out)
    throws Exception
  {
    invoke(_service, in, out);
  }

接下来调用invoke(_service, in, out)函数是整个服务端的核心了,

首先是获取函数名mehtodName,通过methodName = in.readMethod()反序列化来获得函数名

定义函数对象Method method;

然后根据函数名获得函数对象 method = getMethod(methodName);,这里的函数对象是以函数名为key以对象为value存放到map中去的,这样有利于提高性能

   ServiceContext context = ServiceContext.getContext();

    // backward compatibility for some frameworks that don't read
    // the call type first
    in.skipOptionalCall();

    // Hessian 1.0 backward compatibility
    String header;
    while ((header = in.readHeader()) != null) {
      Object value = in.readObject();

      context.addHeader(header, value);
    }

    String methodName = in.readMethod();
    int argLength = in.readMethodArgLength();

    Method method;

    method = getMethod(methodName + "__" + argLength);

    if (method == null)
      method = getMethod(methodName);

既然都已经拿到函数对象了,当然接下来的操作就是执行客户端要调用的函数了,这也是服务端的关键

method.getParameterTypes获得参数类型

Object []values = new Object[args.length];创建参数对象数组

values[i] = in.readObject(args[i]);反序列化客户端发送过来的参数值

result = method.invoke(service, values); 通过反射调用客户端想要调用的函数,并返回结果。

out.writeReply(result);对结果值进行序列化并发送给客户端,这样整个的RPC的调用过程就结束了。

 <span style="white-space:pre">	</span>Class<?> []args = method.getParameterTypes();

    if (argLength != args.length && argLength >= 0) {
      out.writeFault("NoSuchMethod",
                     escapeMessage("method " + method + " argument length mismatch, received length=" + argLength),
                     null);
      out.close();
      return;
    }

    Object []values = new Object[args.length];

    for (int i = 0; i < args.length; i++) {
      // XXX: needs Marshal object
      values[i] = in.readObject(args[i]);
    }

    Object result = null;

    try {
      result = method.invoke(service, values);
    } catch (Exception e) {
      Throwable e1 = e;
      if (e1 instanceof InvocationTargetException)
        e1 = ((InvocationTargetException) e).getTargetException();

      log.log(Level.FINE, this + " " + e1.toString(), e1);

      out.writeFault("ServiceException",
                     escapeMessage(e1.getMessage()),
                     e1);
      out.close();
      return;
    }

    // The complete call needs to be after the invoke to handle a
    // trailing InputStream
    in.completeCall();

    out.writeReply(result);

    out.close();

总结:RPC机制就是客户端发送给服务端想要调用的函数及参数值,服务端通过客户端发送过来的函数和参数值通过反射机制进行函数调用执行,然后将执行结果返回给客户端,这样一个RPC的调用过程结束了。

HessianSkeleton完整源码:

public class HessianSkeleton extends AbstractSkeleton {
  private static final Logger log
    = Logger.getLogger(HessianSkeleton.class.getName());

  private boolean _isDebug;

  private HessianInputFactory _inputFactory = new HessianInputFactory();
  private HessianFactory _hessianFactory = new HessianFactory();

  private Object _service;

  /**
   * Create a new hessian skeleton.
   *
   * @param service the underlying service object.
   * @param apiClass the API interface
   */
  public HessianSkeleton(Object service, Class<?> apiClass)
  {
    super(apiClass);

    if (service == null)
      service = this;

    _service = service;

    if (! apiClass.isAssignableFrom(service.getClass()))
      throw new IllegalArgumentException("Service " + service + " must be an instance of " + apiClass.getName());
  }

  /**
   * Create a new hessian skeleton.
   *
   * @param service the underlying service object.
   * @param apiClass the API interface
   */
  public HessianSkeleton(Class<?> apiClass)
  {
    super(apiClass);
  }

  public void setDebug(boolean isDebug)
  {
    _isDebug = isDebug;
  }

  public boolean isDebug()
  {
    return _isDebug;
  }

  public void setHessianFactory(HessianFactory factory)
  {
    _hessianFactory = factory;
  }

  /**
   * Invoke the object with the request from the input stream.
   *
   * @param in the Hessian input stream
   * @param out the Hessian output stream
   */
  public void invoke(InputStream is, OutputStream os)
    throws Exception
  {
    invoke(is, os, null);
  }

  /**
   * Invoke the object with the request from the input stream.
   *
   * @param in the Hessian input stream
   * @param out the Hessian output stream
   */
  public void invoke(InputStream is, OutputStream os,
                     SerializerFactory serializerFactory)
    throws Exception
  {
    boolean isDebug = false;

    if (isDebugInvoke()) {
      isDebug = true;

      PrintWriter dbg = createDebugPrintWriter();
      HessianDebugInputStream dIs = new HessianDebugInputStream(is, dbg);
      dIs.startTop2();
      is = dIs;
      HessianDebugOutputStream dOs = new HessianDebugOutputStream(os, dbg);
      dOs.startTop2();
      os = dOs;
    }

    HessianInputFactory.HeaderType header = _inputFactory.readHeader(is);

    AbstractHessianInput in;
    AbstractHessianOutput out;
	//通过头部信息来选择序列化和反序列化方式
    switch (header) {
    case CALL_1_REPLY_1:
      in = _hessianFactory.createHessianInput(is);
      out = _hessianFactory.createHessianOutput(os);
      break;

    case CALL_1_REPLY_2:
      in = _hessianFactory.createHessianInput(is);
      out = _hessianFactory.createHessian2Output(os);
      break;

    case HESSIAN_2:
      in = _hessianFactory.createHessian2Input(is);
      in.readCall();
      out = _hessianFactory.createHessian2Output(os);
      break;

    default:
      throw new IllegalStateException(header + " is an unknown Hessian call");
    }

    if (serializerFactory != null) {
      in.setSerializerFactory(serializerFactory);
      out.setSerializerFactory(serializerFactory);
    }

    try {
      invoke(_service, in, out);
    } finally {
      in.close();
      out.close();

      if (isDebug)
        os.close();
    }
  }

  /**
   * Invoke the object with the request from the input stream.
   *
   * @param in the Hessian input stream
   * @param out the Hessian output stream
   */
  public void invoke(AbstractHessianInput in, AbstractHessianOutput out)
    throws Exception
  {
    invoke(_service, in, out);
  }

  /**
   * Invoke the object with the request from the input stream.
   *
   * @param in the Hessian input stream
   * @param out the Hessian output stream
   */
  public void invoke(Object service,
                     AbstractHessianInput in,
                     AbstractHessianOutput out)
    throws Exception
  {
    ServiceContext context = ServiceContext.getContext();

    // backward compatibility for some frameworks that don't read
    // the call type first
    in.skipOptionalCall();

    // Hessian 1.0 backward compatibility
    String header;
    while ((header = in.readHeader()) != null) {
      Object value = in.readObject();

      context.addHeader(header, value);
    }
	//反序列化获得客户端发送过来的函数名
    String methodName = in.readMethod();
    int argLength = in.readMethodArgLength();

    Method method;
	//从map中获取Method对象
    method = getMethod(methodName + "__" + argLength);

    if (method == null)
      method = getMethod(methodName);

    if (method != null) {
    }
    else if ("_hessian_getAttribute".equals(methodName)) {
      String attrName = in.readString();
      in.completeCall();

      String value = null;

      if ("java.api.class".equals(attrName))
        value = getAPIClassName();
      else if ("java.home.class".equals(attrName))
        value = getHomeClassName();
      else if ("java.object.class".equals(attrName))
        value = getObjectClassName();

      out.writeReply(value);
      out.close();
      return;
    }
    else if (method == null) {
      out.writeFault("NoSuchMethodException",
                     escapeMessage("The service has no method named: " + in.getMethod()),
                     null);
      out.close();
      return;
    }
	//获得参数值类型
    Class<?> []args = method.getParameterTypes();

    if (argLength != args.length && argLength >= 0) {
      out.writeFault("NoSuchMethod",
                     escapeMessage("method " + method + " argument length mismatch, received length=" + argLength),
                     null);
      out.close();
      return;
    }

    Object []values = new Object[args.length];

    for (int i = 0; i < args.length; i++) {
      // XXX: needs Marshal object
	  //函数的参数值
      values[i] = in.readObject(args[i]);
    }

    Object result = null;

    try {
	   //反射执行客户端想要执行的函数
      result = method.invoke(service, values);
    } catch (Exception e) {
      Throwable e1 = e;
      if (e1 instanceof InvocationTargetException)
        e1 = ((InvocationTargetException) e).getTargetException();

      log.log(Level.FINE, this + " " + e1.toString(), e1);

      out.writeFault("ServiceException",
                     escapeMessage(e1.getMessage()),
                     e1);
      out.close();
      return;
    }

    // The complete call needs to be after the invoke to handle a
    // trailing InputStream
	//调用结束
    in.completeCall();
	//对结果值进行序列化,并发送给客户端
    out.writeReply(result);

    out.close();
  }
  //以下是和日志相关的,不会影响主流程
  private String escapeMessage(String msg)
  {
    if (msg == null)
      return null;

    StringBuilder sb = new StringBuilder();

    int length = msg.length();
    for (int i = 0; i < length; i++) {
      char ch = msg.charAt(i);

      switch (ch) {
      case '<':
        sb.append("<");
        break;
      case '>':
        sb.append(">");
        break;
      case 0x0:
        sb.append("�");
        break;
      case '&':
        sb.append("&");
        break;
      default:
        sb.append(ch);
        break;
      }
    }

    return sb.toString();
  }

  protected boolean isDebugInvoke()
  {
    return (log.isLoggable(Level.FINEST)
            || isDebug() && log.isLoggable(Level.FINE));
  }

  /**
   * Creates the PrintWriter for debug output. The default is to
   * write to java.util.Logging.
   */
  protected PrintWriter createDebugPrintWriter()
    throws IOException
  {
    return new PrintWriter(new LogWriter(log));
  }

  static class LogWriter extends Writer {
    private Logger _log;
    private StringBuilder _sb = new StringBuilder();

    LogWriter(Logger log)
    {
      _log = log;
    }

    public void write(char ch)
    {
      if (ch == '\n' && _sb.length() > 0) {
        _log.fine(_sb.toString());
        _sb.setLength(0);
      }
      else
        _sb.append((char) ch);
    }

    public void write(char []buffer, int offset, int length)
    {
      for (int i = 0; i < length; i++) {
        char ch = buffer[offset + i];

        if (ch == '\n' && _sb.length() > 0) {
          _log.fine(_sb.toString());
          _sb.setLength(0);
        }
        else
          _sb.append((char) ch);
      }
    }

    public void flush()
    {
    }

    public void close()
    {
    }
  }
}

Hessian源码分析--HessianSkeleton的更多相关文章

  1. Hessian源码分析--总体架构

    Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebService,Hessian更简单.快捷.采用的是二进制RPC协议,因为采用的是二进制协 ...

  2. Hessian源码分析--HessianProxy

    在上一篇博客 Hessian源码分析--HessianProxyFactory 中我们了解到,客户端获得的对象其实是HessianProxy生成的目标对象,当调用目标对象的方法时,会调用Hessian ...

  3. (转)hessian源码分析(一)------架构

    在计费中心的对外交互这块采用了hessian,有必要对hessian的运行机理和源码做一定的解析. 大致翻了翻源码后,发现hessian的主要结构分客户端与服务端,中间基于http传输.客户端主要做的 ...

  4. Hessian源码分析--HessianServlet

    Hessian可以通过Servlet来对外暴露服务,HessianServlet继承于HttpServlet,但这仅仅是一个外壳,使用web服务器来提供对外的Http请求,在web.xml中我们会进行 ...

  5. Hessian源码分析--HessianProxyFactory

    HessianProxyFactory是HessianProxy的工厂类,其通过HessianProxy来生成代理类. 如下面代码: HessianProxyFactory factory = new ...

  6. SURF算法与源码分析、下

    上一篇文章 SURF算法与源码分析.上 中主要分析的是SURF特征点定位的算法原理与相关OpenCV中的源码分析,这篇文章接着上篇文章对已经定位到的SURF特征点进行特征描述.这一步至关重要,这是SU ...

  7. Dubbo 源码分析 - 服务引用

    1. 简介 在上一篇文章中,我详细的分析了服务导出的原理.本篇文章我们趁热打铁,继续分析服务引用的原理.在 Dubbo 中,我们可以通过两种方式引用远程服务.第一种是使用服务直联的方式引用服务,第二种 ...

  8. 【OpenCV】SIFT原理与源码分析:关键点搜索与定位

    <SIFT原理与源码分析>系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html 由前一步<DoG尺度空间构造>,我们得到了 ...

  9. 12.源码分析—如何为SOFARPC写一个序列化?

    SOFARPC源码解析系列: 1. 源码分析---SOFARPC可扩展的机制SPI 2. 源码分析---SOFARPC客户端服务引用 3. 源码分析---SOFARPC客户端服务调用 4. 源码分析- ...

随机推荐

  1. SpringCache学习之操作redis

    一.redis快速入门 1.redis简介 在java领域,常见的四大缓存分别是ehcache,memcached,redis,guava-cache,其中redis与其他类型缓存相比,有着得天独厚的 ...

  2. box-sizing position

    box-sizing 属性 用于更改用于计算元素宽度和高度的默认的 CSS 盒子模型.可以使用此属性来模拟不正确支持CSS盒子模型规范的浏览器的行为. /* 关键字 值 */ box-sizing: ...

  3. 算法工程师:双非渣硕是如何获得百度、京东双SP

    本人本科硕士皆双非,和牛客大佬们没得比,目前拿到的还可以的offer就是百度SP和京东SP,都是做的推荐算法,其他的不说了. 先说一下个人经历吧,学校比较水,实验室没有项目,实习经历:腾讯实习+滴滴实 ...

  4. 利用Runtime实现简单的字典转模型

    前言 我们都知道,开发中会有这么一个过程,就是将服务器返回的数据转换成我们自己定义的模型对象.当然服务器返回的数据结构有xml类型的,也有json类型的.本文只讨论json格式的. 大家在项目中一般是 ...

  5. 反射实现java深度克隆

    一.克隆 有时想得到对象的一个复制品,该复制品的实体是原对象实体的克隆.复制品实体的变化不会引起原对象实体发生变化,这样的复制品称为原对象实体的克隆对象或简称克隆. 1.浅复制(浅克隆) 概念:被复制 ...

  6. hibernate实体对象的三种状态:自由状态,持久状态,游离状态.

    自由态与游离态的区别: 当一个持久化对象,脱离开Hibernate的缓存管理后,它就处于游离状态,游离对象和自由对象的最大区别在于,游离对象在数据库中可能还存在一条与它 对应的记录,只是现在这个游离对 ...

  7. Python中and(逻辑与)计算法则

    在程序设计中,and称为逻辑与运算,也称布尔运算:1.and是在布尔上下文中从左到右计算表达式的值:2.0.''.[].().{}.None.False在布尔上下文中为假:其它任何东西都为真:3.如果 ...

  8. Go语言-通道类型

    通道(Channel)是Go语言中一种非常独特的数据结构.它可用于在不同Goroutine之间传递类型化的数据,并且是并发安全的.相比之下,我们之前介绍的那些数据类型都不是并发安全的.这一点需要特别注 ...

  9. Linux操作系统进程模型分析进程

    Linux操作系统简介 Linux拥有现代操作系统的功能,如真正的抢先式多任务处理,支持多用户内存,保护虚拟内存,支持SMP.UP,符合POSIX 标准联网.图形用户接口和桌面环境具有快速性.稳定性等 ...

  10. Linux 下不经过BIOS重启(i386)

    前段时间有个项目,要求在Linux下不经过BIOS重启,i386平台. 一.可行性分析 众所周知,BIOS中包含了CPU及其他各种设备的初始化代码,Linux系统运行之后是否能够将各种用到的设备返回到 ...