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. 源码分析- ...
随机推荐
- Spring源码分析(一)--BeanProcessor
一.何谓BeanProcessor BeanProcessor是SpringFramework里非常重要的核心接口之一,我先贴出一段源代码: /* * Copyright 2002-2015 the ...
- Java web 前端面试知识点总结
经过几家大厂面试,目前成功拿到唯品会offer,分享一下我的面试知识点总结: 耦合性:也称块间联系.指软件系统结构中各模块间相互联系紧密程度的一种度量.模块之间联系越紧密,其耦合性就越强,模块的独立性 ...
- Linux必备操作vim
vim被称作为编辑器之神,那么在我们操作linux系统时,进行编辑操作有没有感觉心有余而力不足?今天我讲自己总结的一些vim的操作命令和大家进行一下分享,有不足之处还请指出. vim的三种模式大家还记 ...
- windows server 2003 远程桌面最大连接数调整与windows 2008远程桌面后,本地帐号自动锁定
调整windows server 2003 最大远程连接数的步骤如下: 第1步.开始-->控制面板-->添加或删除程序-->添加/删除windows组件-->选择"终 ...
- samba服务器配置过程
SAMBA服务器配置 yum install samba samba-client samba-swat 改变文件权限及用户 vi /etc/samba/smb.conf d+G全删注释 复制下面代码 ...
- kafka简单回顾
先说说遇到的坑 回顾下kafka topic:生产组:P0\P1----P14 一个消费组:c0 c1 c2 依据Consumer的负载均衡分配 消费顺序"c0:p0-p4 c1:p5-p9 ...
- JAVA反射之Class类的练习
package zhang; /** * JAVA反射之CLass类的练习 * * 在面向对象的语言里,万事万物皆对象,那么类是谁的对象呢? * 类的类型是CLass * * */ class Tes ...
- Eleven
A. Eleven time limit per test : 1 second memory limit per test: 256 megabytes input: standard inpu ...
- Node.js 子进程
稳定性: 3 - 稳定 Node 通过 child_process 模块提供了 popen(3) 数据流. 它能在非阻塞的方式中,通过 stdin, stdout, 和 stderr 传递数据. (请 ...
- Django的配置文件(settings)
静态文件设置: 一.概述: #静态文件交由Web服务器处理,Django本身不处理静态文件.简单的处理逻辑如下(以nginx为例): # URI请求-----> 按照Web服务器里面的配置规则先 ...