Hessian源码分析

hessian的主要结构分客户端与服务端,中间基于http传输。客户端主要做的事情是把对远程接口调用序列化为流,并传输到服务端;服务端主要做的事情是把传输过来的流反序列化为对服务的请求,调用相应服务后把结果序列化为流返回给客户端。一次完整的调用如下图所示:

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

 

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

 

 

 

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

 

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

 

[java]  view plain copy
  1. public Object invoke(Object proxy, Method method, Object []args)  
  2.     throws Throwable  
  3.   {  
  4.     String mangleName;  
  5.     synchronized (_mangleMap) {  
  6.       mangleName = _mangleMap.get(method);  
  7.     }  
  8.     if (mangleName == null) {  
  9.       String methodName = method.getName();  
  10.       Class []params = method.getParameterTypes();  
  11.       // equals and hashCode are special cased  
  12.       if (methodName.equals("equals")  
  13.       && params.length == 1 && params[0].equals(Object.class)) {  
  14.     Object value = args[0];  
  15.     if (value == null || ! Proxy.isProxyClass(value.getClass()))  
  16.       return new Boolean(false);  
  17.     HessianProxy handler = (HessianProxy) Proxy.getInvocationHandler(value);  
  18.     return new Boolean(_url.equals(handler.getURL()));  
  19.       }  
  20.       else if (methodName.equals("hashCode") && params.length == 0)  
  21.     return new Integer(_url.hashCode());  
  22.       else if (methodName.equals("getHessianType"))  
  23.     return proxy.getClass().getInterfaces()[0].getName();  
  24.       else if (methodName.equals("getHessianURL"))  
  25.     return _url.toString();  
  26.       else if (methodName.equals("toString") && params.length == 0)  
  27.     return "HessianProxy[" + _url + "]";  
  28.         
  29.       if (! _factory.isOverloadEnabled())  
  30.     mangleName = method.getName();  
  31.       else  
  32.         mangleName = mangleName(method);  
  33.       synchronized (_mangleMap) {  
  34.     _mangleMap.put(method, mangleName);  
  35.       }  
  36.     }  
  37.     ......  
  38. }  

 

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

接着往下看:

 

[java]  view plain copy
  1. public Object invoke(Object proxy, Method method, Object []args)  
  2.     throws Throwable  
  3.   {  
  4.     ......  
  5.     InputStream is = null;  
  6.     URLConnection conn = null;  
  7.     HttpURLConnection httpConn = null;  
  8.       
  9.     try {  
  10.              
  11.       conn = sendRequest(mangleName, args);  
  12.      ......  
  13.     } catch (HessianProtocolException e) {  
  14.       throw new HessianRuntimeException(e);  
  15.     } finally {  
  16.      ......  
  17.      }  
  18.   }  

 

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

 

[java:nogutter]  view plain copy
  1. protected URLConnection sendRequest(String methodName, Object []args)  
  2.     throws IOException  
  3.   {  
  4.     URLConnection conn = null;  
  5.       
  6.     conn = _factory.openConnection(_url);  
  7.     boolean isValid = false;  
  8.     try {  
  9.       // Used chunked mode when available, i.e. JDK 1.5.  
  10.       if (_factory.isChunkedPost() && conn instanceof HttpURLConnection) {  
  11.     try {  
  12.       HttpURLConnection httpConn = (HttpURLConnection) conn;  
  13.       httpConn.setChunkedStreamingMode(8 * 1024);  
  14.     } catch (Throwable e) {  
  15.     }  
  16.       }  
  17.       
  18.       addRequestHeaders(conn);  
  19.       OutputStream os = null;  
  20.       try {  
  21.     os = conn.getOutputStream();  
  22.       } catch (Exception e) {  
  23.     throw new HessianRuntimeException(e);  
  24.       }  
  25.       if (log.isLoggable(Level.FINEST)) {  
  26.     PrintWriter dbg = new PrintWriter(new LogWriter(log));  
  27.     os = new HessianDebugOutputStream(os, dbg);  
  28.       }  
  29.         
  30.       AbstractHessianOutput out = _factory.getHessianOutput(os);  
  31.       out.call(methodName, args);  
  32.       out.flush();  
  33.       isValid = true;  
  34.       return conn;  
  35.     } finally {  
  36.       if (! isValid && conn instanceof HttpURLConnection)  
  37.     ((HttpURLConnection) conn).disconnect();  
  38.     }  
  39.   }  

 

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

下面接着看invoke方法:

 

[java:nogutter]  view plain copy
  1. public Object invoke(Object proxy, Method method, Object []args)  
  2.     throws Throwable  
  3.   {  
  4.       ......  
  5.       is = conn.getInputStream();  
  6.       AbstractHessianInput in = _factory.getHessianInput(is);  
  7.       in.startReply();  
  8.       Object value = in.readObject(method.getReturnType());  
  9.       if (value instanceof InputStream) {  
  10.     value = new ResultInputStream(httpConn, is, in, (InputStream) value);  
  11.     is = null;  
  12.     httpConn = null;  
  13.       }  
  14.       else  
  15.     in.completeReply();  
  16.       ......  
  17.   }  

 

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

 

HessianSkeleton是Hessian server端的核心类,主要功能是接收网络输入流(被包装为AbstractHessianInput),反序列化输入流得到methodName和参数,然后调用服务端的服务,得到结果后序列化为输出流,返回给客户端,主要流程如下图所示:

HessianSkeleton的核心代码如下所示:

 

[java:nogutter]  view plain copy
  1. public void invoke(Object service,  
  2.              AbstractHessianInput in,  
  3.              AbstractHessianOutput out)  
  4.     throws Exception  
  5.   {  
  6.     ......      
  7.     String methodName = in.readMethod();  
  8.     Method method = getMethod(methodName);  
  9.     ......  
  10.     Class []args = method.getParameterTypes();  
  11.     Object []values = new Object[args.length];  
  12.     for (int i = 0; i < args.length; i++) {  
  13.       values[i] = in.readObject(args[i]);  
  14.     }  
  15.     Object result = null;  
  16.       
  17.     try {  
  18.       result = method.invoke(service, values);  
  19.     } catch (Throwable e) {  
  20.       ......  
  21.     }  
  22.     // The complete call needs to be after the invoke to handle a  
  23.     // trailing InputStream  
  24.     in.completeCall();  
  25.       
  26.     out.startReply();  
  27.     out.writeObject(result);  
  28.       
  29.     out.completeReply();  
  30.     out.close();  
  31.   }  

 

主流程代码非常清晰,不需要太多解释,关键的地方在于对网络流的序列化和反序列化,我会在hessian io分析的部分中进行详细阐述

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值