Hessian源码分析--HessianSkeleton
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的更多相关文章
- Hessian源码分析--总体架构
Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebService,Hessian更简单.快捷.采用的是二进制RPC协议,因为采用的是二进制协 ...
- Hessian源码分析--HessianProxy
在上一篇博客 Hessian源码分析--HessianProxyFactory 中我们了解到,客户端获得的对象其实是HessianProxy生成的目标对象,当调用目标对象的方法时,会调用Hessian ...
- (转)hessian源码分析(一)------架构
在计费中心的对外交互这块采用了hessian,有必要对hessian的运行机理和源码做一定的解析. 大致翻了翻源码后,发现hessian的主要结构分客户端与服务端,中间基于http传输.客户端主要做的 ...
- Hessian源码分析--HessianServlet
Hessian可以通过Servlet来对外暴露服务,HessianServlet继承于HttpServlet,但这仅仅是一个外壳,使用web服务器来提供对外的Http请求,在web.xml中我们会进行 ...
- Hessian源码分析--HessianProxyFactory
HessianProxyFactory是HessianProxy的工厂类,其通过HessianProxy来生成代理类. 如下面代码: HessianProxyFactory factory = new ...
- SURF算法与源码分析、下
上一篇文章 SURF算法与源码分析.上 中主要分析的是SURF特征点定位的算法原理与相关OpenCV中的源码分析,这篇文章接着上篇文章对已经定位到的SURF特征点进行特征描述.这一步至关重要,这是SU ...
- Dubbo 源码分析 - 服务引用
1. 简介 在上一篇文章中,我详细的分析了服务导出的原理.本篇文章我们趁热打铁,继续分析服务引用的原理.在 Dubbo 中,我们可以通过两种方式引用远程服务.第一种是使用服务直联的方式引用服务,第二种 ...
- 【OpenCV】SIFT原理与源码分析:关键点搜索与定位
<SIFT原理与源码分析>系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html 由前一步<DoG尺度空间构造>,我们得到了 ...
- 12.源码分析—如何为SOFARPC写一个序列化?
SOFARPC源码解析系列: 1. 源码分析---SOFARPC可扩展的机制SPI 2. 源码分析---SOFARPC客户端服务引用 3. 源码分析---SOFARPC客户端服务调用 4. 源码分析- ...
随机推荐
- day4 liaoxuefeng--调试、线程、正则表达式
一.错误.调试和测试 二.进程和线程 三.正则表达式
- Axis2 webservice入门--Webservice的发布与调用
一.Webservice发布 参考 http://www.cnblogs.com/demingblog/p/3263576.html 二.webservice 调用 部分参考:http://www.c ...
- Promise--优雅的异步回调解决方案
当一个接口需要依赖另一个接口的请求数据时,通常有两种解决方式,一个是将请求数据的接口设为同步,之后调另一个接口,另一个是在请求数据接口的成功回调里调另一个接口. 但是:当一个接口需要依赖很多个接口的请 ...
- 如果将Joomla网站搜索结果显示到一个“干净”页面
有时候大家会发现Joomla网站自带的或者第三方的搜索功能时,搜索结果会显示在首页,和首页其它的模块如图片橱窗等显示在一起,非常混乱. 在这里教大家一个不需要修改代码的小技巧来解决这个问题,使搜索结果 ...
- 最小费用最大流(luogu P3381 【模板】最小费用最大流)
题目链接 题目描述 如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S. ...
- ThreadLocal 遇上线程池的问题及解决办法
ThreadLocal 称为线程本地存储,它为每一个使用它的线程提供一个其值(value)的副本.可以将 ThreadLocal<T> 理解成 Map<Thread, T>,即 ...
- Android需求之点击跳转至市场评价
相信大家都看过APP上有一个选项"喜欢此APP?还希望您评价一下吧!",然后点击弹出选择框让你选择一个市场如: 安智市场,百度应用,豌豆荚-.然后选择其中一个后就跳转至此市场你的A ...
- Android Multimedia框架总结(二十四)MediaMuxer实现手机屏幕录制成gif图
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53866405 前言:上篇中,介绍 ...
- Git之(六)标签管理
发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本.将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来.所以,标签也是版本库的一个快照 ...
- PGM:基于模板的表示
http://blog.csdn.net/pipisorry/article/details/52537660 引言 概率图模型(无论贝叶斯网或马尔可夫网)在一个固定的随机变量集X上具体指定了一个联合 ...