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. 源码分析- ...
随机推荐
- Django+nginx+uwsgi部署教程(centos7+ubuntu16.4)
在线教育平台项目演示地址 项目部署教程 1.1.工作原理介绍 django 一个基于python的开源web框架 uwsgi 一是一个web服务器,也可以当做中间件 nginx 常用高性能代理服务器 ...
- 关于ajax的content-download时间过慢问题的解决方案与思考
前言: 做前端架构很久很久了,经常到我这里都是些棘手的问题,之前没有养成很好的记录问题的习惯,以后会努力成文,积累. 于是今天就有个这篇文章.关于ajax的content-download时间过慢 ...
- 关于html+ashx开发中几个问题的解决方法
在跟html+ashx打交道的园友们肯定会发现,这种模式虽然优美,但在开发中会遇到一些难处理的地方.我也不例外,下面是自己在实际开发中总结出来的几条经验,希望跟大家分享,更希望得到大家的建议和更好的解 ...
- ActiveMQ消息传递的两种方式
1.什么是ActiveMQ? ActiveMQ是apache提供的开源的,实现消息传递的一个中间插件,可以和spring整合,是目前最流行的开源消息总线,ActiveMQ是一个完全支持JMS1.1和J ...
- 渗透测试环境DVWA搭建
一.DVWA介绍 DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供 ...
- git 覆盖本地变化
git fetch && git reset --hard origin/master
- 20160213.CCPP体系详解(0023天)
程序片段(01):全排列.c 内容概要:全排列密码库 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <std ...
- docker iotop :OSError: Netlink error: No such file or directory
在容器内使用iotop ,错误信息: raceback (most recent call last): File "/usr/sbin/iotop", line 16, in & ...
- iOS-改变UITextField的Placeholder颜色的三种方式
转自:http://blog.csdn.net/mazy_ma/article/details/51775670 有时,UITextField自带的Placeholder的颜色太浅或者不满足需求,所以 ...
- Swift基础之音乐播放随机变换着色板
今天的内容比较简单,我也就不做详细的文字介绍了,直接上代码,希望对大家有所帮助 var audioPlayer = AVAudioPlayer() //梯度配色 let gradientL ...