您的位置:首页 > 其它

hessian原理服务端源码分析(三)

2017-11-02 13:49 316 查看
上一篇文章分析了hessian客户端的源码,其实服务端的源码分析与客户端的差不多,只是服务端是先接收客户端的请求,将请求参数进行反序列化,再处理,将结果序列化转换成流返回给客户端,由于有了客户端源码分析,其他的就不多说了,直接上代码

1.为了能够跟进hessian服务端的源码,首先我们需要将导入hessian的jar包替换成源码,下面是我导入hessian源码的目录结构:



2.根据我们在hessian web中的web.xml配置的hessian servlet可知,接收客户端的请求是从HessianServlet中的service方法开始的,那么我们就在这个方法里面打个断点

调试的快捷方式:

F5进入方法 F6往下执行 F8到达下一个断点

下面是service方法中的代码

HttpServletRequest req = (HttpServletRequest) request;//转换成httpServletRequest
HttpServletResponse res = (HttpServletResponse) response;

if (! req.getMethod().equals("POST")) {//判断请求方法是不是post方法
res.setStatus(500, "Hessian Requires POST");
PrintWriter out = res.getWriter();

res.setContentType("text/html");
out.println("<h1>Hessian Requires POST</h1>");

return;
}

String serviceId = req.getPathInfo();
String objectId = req.getParameter("id");
if (objectId == null)
objectId = req.getParameter("ejbid");

ServiceContext.begin(req, serviceId, objectId);

try {
InputStream is = request.getInputStream();
OutputStream os = response.getOutputStream();

response.setContentType("application/x-hessian");//设置请求类型

if (_log.isLoggable(Level.FINEST)
|| _isDebug && _log.isLoggable(Level.FINE)) {
PrintWriter dbg = new PrintWriter(new LogWriter(_log));
HessianDebugInputStream dIs = new HessianDebugInputStream(is, dbg);
dIs.startTop2();
is = dIs;
HessianDebugOutputStream dOs = new HessianDebugOutputStream(os, dbg);
dOs.startTop2();
os = dOs;
}

int code = is.read();
int major;
int minor;

AbstractHessianInput in;
AbstractHessianOutput out;

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

if (major != 0x02 || minor != 0x00)
throw new IOException("Version " + major + "." + minor + " is not understood");

in = createHessian2Input(is);
out = new Hessian2Output(os);

in.readCall();
}
else if (code == 'c') {
major = is.read();
minor = is.read();

in = new HessianInput(is);//获取hessian自己封装的输入流

if (major >= 2)
out = new Hessian2Output(os);
else
out = new HessianOutput(os);
}
else {
// XXX: deflate
throw new IOException("expected 'H' (Hessian 2.0) or 'c' (Hessian 1.0) in hessian input at " + code);
}

SerializerFactory serializerFactory = getSerializerFactory();//获得序列化工厂将得到的流反序列化
in.setSerializerFactory(serializerFactory);

out.setSerializerFactory(serializerFactory);

if (objectId != null)
_objectSkeleton.invoke(in, out);//处理请求
else
_homeSkeleton.invoke(in, out);//处理请求

out.close();
} catch (RuntimeException e) {
throw e;
} catch (ServletException e) {
throw e;
} catch (Throwable e) {
throw new ServletException(e);
} finally {
ServiceContext.end();
}


我就把里面重要的几行代码单拿出来

if (major >= 2)//用来设置成hessian自己封装的输出流

out = new Hessian2Output(os);

else

out = new HessianOutput(os);

}

in = new HessianInput(is);//获取hessian自己封装的输入流

SerializerFactory serializerFactory = getSerializerFactory();//获得序列化工厂将得到的流反序列化

in.setSerializerFactory(serializerFactory);

out.setSerializerFactory(serializerFactory);

然后

if (objectId != null)

_objectSkeleton.invoke(in, out);//处理请求

else

_homeSkeleton.invoke(in, out);//处理请求

处理请求就交给了HessianSkeleton类,调用其中的invoke方法

继续跟进invoke方法

3.invoke方法代码:

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);

if (method == null) {
out.writeFault("NoSuchMethodException",
"The service has no method named: " + in.getMethod(),
null);
out.close();
return;
}
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;
}

Class []args = method.getParameterTypes();

if (argLength != args.length && argLength >= 0) {
out.writeFault("NoSuchMethod",
"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++) {
values[i] = in.readObject(args[i]);//将参数反序列化
}

Object result = null;

try {
result = method.invoke(service, values);//处理并返回结果
} catch (Throwable e) {
if (e instanceof InvocationTargetException)
e = ((InvocationTargetException) e).getTargetException();

log.log(Level.FINE, this + " " + e.toString(), e);

out.writeFault("ServiceException", e.getMessage(), e);
out.close();
return;
}

// The complete call needs to be after the invoke to handle a
// trailing InputStream
in.completeCall();//将结果序列化之前的准备

out.writeReply(result);//将结果序列化并返回给客户端

out.close();//关闭资源
}


再跟进readObject(Class cl)方法,看看里面是如何将得到的流反序列化的

if (cl == null || cl == Object.class)
return readObject();

int tag = read();

switch (tag) {
case 'N':
return null;

case 'M':
{
String type = readType();

// hessian/3386
if ("".equals(type)) {
Deserializer reader;
reader = _serializerFactory.getDeserializer(cl);

return reader.readMap(this);
}
else {
Deserializer reader;
reader = _serializerFactory.getObjectDeserializer(type);

return reader.readMap(this);
}
}

case 'V':
{
String type = readType();
int length = readLength();

Deserializer reader;
reader = _serializerFactory.getObjectDeserializer(type);

if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))
return reader.readList(this, length);

reader = _serializerFactory.getDeserializer(cl);

Object v = reader.readList(this, length);

return v;
}

case 'R':
{
int ref = parseInt();

return _refs.get(ref);
}

case 'r':
{
String type = readType();
String url = readString();

return resolveRemote(type, url);
}
}

_peek = tag;

// hessian/332i vs hessian/3406
//return readObject();

Object value = _serializerFactory.getDeserializer(cl).readObject(this);

return value;


_serializerFactory.getDeserializer(cl).readObject(this);获取反序列化工厂,并进行反序列化,再跟进这个方法看看

public Object readObject(AbstractHessianInput in)
throws IOException
{
switch (_code) {
case NULL:
// hessian/3490
in.readObject();

return null;

case BOOLEAN:
return Boolean.valueOf(in.readBoolean());

case BYTE:
return Byte.valueOf((byte) in.readInt());

case SHORT:
return Short.valueOf((short) in.readInt());

case INTEGER:
return Integer.valueOf(in.readInt());

case LONG:
return Long.valueOf(in.readLong());

case FLOAT:
return Float.valueOf((float) in.readDouble());

case DOUBLE:
return Double.valueOf(in.readDouble());

case STRING:
return in.readString();

case OBJECT:
return in.readObject();

case CHARACTER:
{
String s = in.readString();
if (s == null || s.equals(""))
return Character.valueOf((char) 0);
else
return Character.valueOf(s.charAt(0));
}

case CHARACTER_OBJECT:
{
String s = in.readString();
if (s == null || s.equals(""))
return null;
else
return Character.valueOf(s.charAt(0));
}

case DATE:
return new Date(in.readUTCDate());

case NUMBER:
return in.readObject();

case BYTE_ARRAY:
return in.readBytes();

case CHARACTER_ARRAY:
{
String s = in.readString();

if (s == null)
return null;
else {
int len = s.length();
char []chars = new char[len];
s.getChars(0, len, chars, 0);
return chars;
}
}

case BOOLEAN_ARRAY:
case SHORT_ARRAY:
case INTEGER_ARRAY:
case LONG_ARRAY:
case FLOAT_ARRAY:
case DOUBLE_ARRAY:
case STRING_ARRAY:
{
int code = in.readListStart();

switch (code) {
case 'N':
return null;

case 0x10: case 0x11: case 0x12: case 0x13:
case 0x14: case 0x15: case 0x16: case 0x17:
case 0x18: case 0x19: case 0x1a: case 0x1b:
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
int length = code - 0x10;
in.readInt();

return readLengthList(in, length);

default:
String type = in.readType();
length = in.readLength();

return readList(in, length);
}
}

default:
throw new UnsupportedOperationException();
}
}


这部分代码就是将得到的流进行反序列化,而后再进行处理,将结果序列化返回到客户端,源码就分析到这里,由于本人水平有限,如果以上解析有误的地方,请留言
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: