`

Hessian源码分析(二)

阅读更多

Hessian在客户端一块采用Proxy模式,当客户端调用远程接口时,HessianProxy会代理这个动作,在invoke方法中,把客户端请求的方法和参数序列化为预订格式的输出流,主要流程如下图所示:

 

下面我将详细解析一下invoke源码:

public Object invoke(Object proxy, Method method, Object []args)
    throws Throwable
  {
    String mangleName;
    synchronized (_mangleMap) {
      mangleName = _mangleMap.get(method);
    }
    if (mangleName == null) {
      String methodName = method.getName();
      Class []params = method.getParameterTypes();
      // equals and hashCode are special cased
      if (methodName.equals("equals")
	  && params.length == 1 && params[0].equals(Object.class)) {
	Object value = args[0];
	if (value == null || ! Proxy.isProxyClass(value.getClass()))
	  return new Boolean(false);
	HessianProxy handler = (HessianProxy) Proxy.getInvocationHandler(value);
	return new Boolean(_url.equals(handler.getURL()));
      }
      else if (methodName.equals("hashCode") && params.length == 0)
	return new Integer(_url.hashCode());
      else if (methodName.equals("getHessianType"))
	return proxy.getClass().getInterfaces()[0].getName();
      else if (methodName.equals("getHessianURL"))
	return _url.toString();
      else if (methodName.equals("toString") && params.length == 0)
	return "HessianProxy[" + _url + "]";
      
      if (! _factory.isOverloadEnabled())
	mangleName = method.getName();
      else
        mangleName = mangleName(method);
      synchronized (_mangleMap) {
	_mangleMap.put(method, mangleName);
      }
    }
    ......
}

 

这是invoke的开头,主要干的事情是把methodName缓存起来和过滤一些特殊调用,java反射是个比较耗性能的操作,把methodName缓存起来可以避免每次调用都要从method里得到methodName。另外,对equals、hashCode、getHessianType、getHessianURL等特殊方法的远程调用,HessianProxy不会走远程调用,而是直接返回。

接着往下看:

public Object invoke(Object proxy, Method method, Object []args)
    throws Throwable
  {
    ......
    InputStream is = null;
    URLConnection conn = null;
    HttpURLConnection httpConn = null;
    
    try {
           
      conn = sendRequest(mangleName, args);
     ......
    } catch (HessianProtocolException e) {
      throw new HessianRuntimeException(e);
    } finally {
     ......
     }
  }

 

这段主要是把方法名和参数序列化为网络输出流,并做网络请求,具体逻辑包装在sendRequest方法中:

protected URLConnection sendRequest(String methodName, Object []args)
    throws IOException
  {
    URLConnection conn = null;
    
    conn = _factory.openConnection(_url);
    boolean isValid = false;
    try {
      // Used chunked mode when available, i.e. JDK 1.5.
      if (_factory.isChunkedPost() && conn instanceof HttpURLConnection) {
	try {
	  HttpURLConnection httpConn = (HttpURLConnection) conn;
	  httpConn.setChunkedStreamingMode(8 * 1024);
	} catch (Throwable e) {
	}
      }
    
      addRequestHeaders(conn);
      OutputStream os = null;
      try {
	os = conn.getOutputStream();
      } catch (Exception e) {
	throw new HessianRuntimeException(e);
      }
      if (log.isLoggable(Level.FINEST)) {
	PrintWriter dbg = new PrintWriter(new LogWriter(log));
	os = new HessianDebugOutputStream(os, dbg);
      }
      
      AbstractHessianOutput out = _factory.getHessianOutput(os);
      out.call(methodName, args);
      out.flush();
      isValid = true;
      return conn;
    } finally {
      if (! isValid && conn instanceof HttpURLConnection)
	((HttpURLConnection) conn).disconnect();
    }
  }

 

sendRequest的主要流程是先初始化网络连接,然后用AbstractHessianOutput包装网络输出流,调用AbstractHessianOutput.call(methodName, args)完成网络输出,这个方法的细节会在hessian io的源码解析中详细分析。

下面接着看invoke方法:

public Object invoke(Object proxy, Method method, Object []args)
    throws Throwable
  {
      ......
      is = conn.getInputStream();
      AbstractHessianInput in = _factory.getHessianInput(is);
      in.startReply();
      Object value = in.readObject(method.getReturnType());
      if (value instanceof InputStream) {
	value = new ResultInputStream(httpConn, is, in, (InputStream) value);
	is = null;
	httpConn = null;
      }
      else
	in.completeReply();
      ......
  }

 

这一段主要是把输入流中取得返回值,具体是用AbstractHessianInput包装网络输入流,然后调用AbstractHessianInput.readObject从网络流中反序列化到实际返回值。

 

分享到:
评论

相关推荐

    Hessian源码分析和Hack.doc

    项目选定Hessian作为web service的实现方式,确实很轻量级,速度就跟直接用socket差不多,全是二进制传送节约了不少开销。但是在使用过程中有业务需要是必须获得远程端的ip地址,主机名等信息的。翻便Hessian的文档...

    hessian最新源码分析.pdf

    hessian最新源码分析.pdf

    JAVA上百实例源码以及开源项目源代码

    内容索引:Java源码,初学实例,二进制,文件复制  Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java...

    JAVA上百实例源码以及开源项目

    内容索引:Java源码,初学实例,二进制,文件复制  Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java...

    一种分割冠状动脉X射线造影图像的有效方法

    方法基于Hessian矩阵的多尺度滤波和区域增长等算法,其中多尺度滤波用来增强造影图像中的血管,然后利用多种子点区域增长算法从增强后的图像中提取冠状动脉树。结果该方法对于造影图像中血管状结构非常敏感,能够清晰...

    java开源包8

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    【JeeSpringCloud v3.2.4】后台权限管理系统+互联网云快速开发框架+微服务分布式代码生成

    另外,REST调用也达到了比较高的性能,在基准测试下,HTTP + JSON默认的RPC协议(即TCP + Hessian2二进制序列化)之间只有1.5倍左右的差距,详见下文的基准测试报告。 ORM/Redis/Service仓库 RepositoryORM仓库,...

    java开源包1

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包11

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包2

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包3

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包6

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包5

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包10

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包4

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包7

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包9

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包101

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    Java资源包01

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

Global site tag (gtag.js) - Google Analytics