当前位置:   article > 正文

hessian原理分析(二)_hessianproxyfactory类作用

hessianproxyfactory类作用

上一篇文章写了一个hessian的入门案例,客户端
HessianProxyFactory factory = new HessianProxyFactory();
try {
HelloHessian helloHessian = (HelloHessian) factory.create(HelloHessian.class, "http://localhost:8080/hessian_web/hessian");
helloHessian.sayHello("hi~~~~~~");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

仅仅有三行重要的代码,那么hessianProxyFactory的作用是什么呢?factory.create的内部实现又是怎么样的呢?,调用sayHello方法里面又是怎么实现的呢?带着这些疑问,接下来我们就一步一步来解决这些谜团
1.hessian客户端访问服务端流程:
hessian的主要结构分为客户端和服务端,中间基于http传输。客户端主要做的就是把对远程调用接口序列化为流,并传输给服务端;而服务端主要是接受客户端的请求,将流反序列化并处理,将结果序列化成流再传输给客户端。下面为流程图:
这里写图片描述
2.hessian是什么呢?
hessian是一种远程通讯协议,它传输的标准格式是二进制文件,而后将二进制文件转化为流(通过序列化方式),以二进制方式传输的方式的好处是可以跨语言进行数据交互,传输便捷,快速
3.HessianProxyFactory通过它的create方法来创建代理类,而这里使用了jdk的动态代理,会自动调用invocationHandler中的invoke方法,HessianProxy实现了InvocationHandler接口
4.接下来就在helloHessian.sayHello(“hi~~~~~~”);
打个断点,然后跟进去,就进入到了invoke方法,

public Object invoke(Object proxy, Method method, Object []args)
throws Throwable
{
String mangleName;

synchronized (_mangleMap) {//_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 Boolean.FALSE;

Object proxyHandler = Proxy.getInvocationHandler(value);

if (! (proxyHandler instanceof HessianProxy))
  return Boolean.FALSE;

HessianProxy handler = (HessianProxy) proxyHandler;

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);//将接口名放入map中
  }
}

InputStream is = null;
URLConnection conn = null;
HttpURLConnection httpConn = null;

try {
  if (log.isLoggable(Level.FINER))
log.finer("Hessian[" + _url + "] calling " + mangleName);

  conn = sendRequest(mangleName, args);//将请求发送给hessian服务端

  if (conn instanceof HttpURLConnection) {
httpConn = (HttpURLConnection) conn;
    int code = 500;

    try {
      code = httpConn.getResponseCode();//获取响应码
    } catch (Exception e) {
    }

    parseResponseHeaders(conn);//解析响应头部信息

    if (code != 200) {
      StringBuffer sb = new StringBuffer();
      int ch;

      try {
        is = httpConn.getInputStream();

        if (is != null) {
          while ((ch = is.read()) >= 0)
            sb.append((char) ch);

          is.close();
        }

        is = httpConn.getErrorStream();
        if (is != null) {
          while ((ch = is.read()) >= 0)
            sb.append((char) ch);
        }
      } catch (FileNotFoundException e) {
        throw new HessianConnectionException("HessianProxy cannot connect to '" + _url, e);
      } catch (IOException e) {
    if (is == null)
      throw new HessianConnectionException(code + ": " + e, e);
    else
      throw new HessianConnectionException(code + ": " + sb, e);
      }

      if (is != null)
        is.close();

      throw new HessianConnectionException(code + ": " + sb.toString());
    }
  }

  is = conn.getInputStream();

  if (log.isLoggable(Level.FINEST)) {
PrintWriter dbg = new PrintWriter(new LogWriter(log));
HessianDebugInputStream dIs
  = new HessianDebugInputStream(is, dbg);

dIs.startTop2();

is = dIs;
  }

  AbstractHessianInput in;

  int code = is.read();

  if (code == 'H') {
int major = is.read();
int minor = is.read();

in = _factory.getHessian2Input(is);

return in.readReply(method.getReturnType());
  }
  else if (code == 'r') {
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();

return value;
  }
  else
throw new HessianProtocolException("'" + (char) code + "' is an unknown code");
} catch (HessianProtocolException e) {
  throw new HessianRuntimeException(e);
} finally {
  try {
if (is != null)
  is.close();
  } catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
  }

  try {
if (httpConn != null)
  httpConn.disconnect();
  } catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159

}
invoke方法中的最重要的几行代码
conn = sendRequest(mangleName, args);//将请求发送给hessian服务端
这行代码主要是建立与服务端的连接并发送请求给服务端,接着我们就跟进去这个方法

URLConnection conn = null;

    conn = _factory.openConnection(_url);//打开与hessian服务器的连接
    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;//转成HttpURLConnection

      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);//获得hessian封装好的输出流

      out.call(methodName, args);//里面就是将方法与参数进行序列化
      out.flush();

      isValid = true;

      return conn;
    } finally {
      if (! isValid && conn instanceof HttpURLConnection)
    ((HttpURLConnection) conn).disconnect();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

接着再跟进out.call(method ,args)方法
int length = args != null ? args.length : 0;

startCall(method, length);//发送连接前准备

for (int i = 0; i < length; i++)
  writeObject(args[i]);//将参数序列化

completeCall();//发送后处理
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

writeObject(args[i])方法就是讲参数进行序列化,再跟进去看看是如何进行序列化的
if (object == null) {
writeNull();
return;
}

Serializer serializer;

serializer = _serializerFactory.getSerializer(object.getClass());//获得序列化工厂

serializer.writeObject(object, this);这里获取序列化工厂,在通过序列化实例将参数进行序列化,再跟进去
  • 1
  • 2
  • 3
  • 4
  • 5
 switch (code) {
    case BOOLEAN:
      out.writeBoolean(((Boolean) obj).booleanValue());
      break;

    case BYTE:
    case SHORT:
    case INTEGER:
      out.writeInt(((Number) obj).intValue());
      break;

    case LONG:
      out.writeLong(((Number) obj).longValue());
      break;

    case FLOAT:
    case DOUBLE:
      out.writeDouble(((Number) obj).doubleValue());
      break;

    case CHARACTER:
    case CHARACTER_OBJECT:
      out.writeString(String.valueOf(obj));
      break;

    case STRING:
      out.writeString((String) obj);
      break;

    case DATE:
      out.writeUTCDate(((Date) obj).getTime());
      break;

    case BOOLEAN_ARRAY:
    {
      if (out.addRef(obj))
        return;

      boolean []data = (boolean []) obj;
      boolean hasEnd = out.writeListBegin(data.length, "[boolean");
      for (int i = 0; i < data.length; i++)
        out.writeBoolean(data[i]);

      if (hasEnd)
    out.writeListEnd();

      break;
    }

    case BYTE_ARRAY:
    {
      byte []data = (byte []) obj;
      out.writeBytes(data, 0, data.length);
      break;
    }

    case SHORT_ARRAY:
    {
      if (out.addRef(obj))
        return;

      short []data = (short []) obj;
      boolean hasEnd = out.writeListBegin(data.length, "[short");

      for (int i = 0; i < data.length; i++)
        out.writeInt(data[i]);

      if (hasEnd)
    out.writeListEnd();
      break;
    }

    case INTEGER_ARRAY:
    {
      if (out.addRef(obj))
        return;

      int []data = (int []) obj;

      boolean hasEnd = out.writeListBegin(data.length, "[int");

      for (int i = 0; i < data.length; i++)
        out.writeInt(data[i]);

      if (hasEnd)
    out.writeListEnd();

      break;
    }

    case LONG_ARRAY:
    {
      if (out.addRef(obj))
        return;

      long []data = (long []) obj;

      boolean hasEnd = out.writeListBegin(data.length, "[long");

      for (int i = 0; i < data.length; i++)
        out.writeLong(data[i]);

      if (hasEnd)
    out.writeListEnd();
      break;
    }

    case FLOAT_ARRAY:
    {
      if (out.addRef(obj))
        return;

      float []data = (float []) obj;

      boolean hasEnd = out.writeListBegin(data.length, "[float");

      for (int i = 0; i < data.length; i++)
        out.writeDouble(data[i]);

      if (hasEnd)
    out.writeListEnd();
      break;
    }

    case DOUBLE_ARRAY:
    {
      if (out.addRef(obj))
        return;

      double []data = (double []) obj;
      boolean hasEnd = out.writeListBegin(data.length, "[double");

      for (int i = 0; i < data.length; i++)
        out.writeDouble(data[i]);

      if (hasEnd)
    out.writeListEnd();
      break;
    }

    case STRING_ARRAY:
    {
      if (out.addRef(obj))
        return;

      String []data = (String []) obj;

      boolean hasEnd = out.writeListBegin(data.length, "[string");

      for (int i = 0; i < data.length; i++) {
        out.writeString(data[i]);
      }

      if (hasEnd)
    out.writeListEnd();
      break;
    }

    case CHARACTER_ARRAY:
    {
      char []data = (char []) obj;
      out.writeString(data, 0, data.length);
      break;
    }

    case OBJECT_ARRAY:
    {
      if (out.addRef(obj))
        return;

      Object []data = (Object []) obj;

      boolean hasEnd = out.writeListBegin(data.length, "[object");

      for (int i = 0; i < data.length; i++) {
        out.writeObject(data[i]);
      }

      if (hasEnd)
    out.writeListEnd();
      break;
    }

    case NULL:
      out.writeNull();
      break;

    default:
      throw new RuntimeException(code + " " + String.valueOf(obj.getClass()));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190

以上代码片段就是对参数进行序列化,客户端的源码分析就到这里,服务端的今后会继续更新,由于本人目前水平有限,对序列化原理还处于比较模糊的状态,下面给大家推荐一篇讲解序列化的文章:
http://www.cnblogs.com/redcreen/articles/1955307.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/1011975
推荐阅读
相关标签
  

闽ICP备14008679号