赞
踩
上一篇文章写了一个hessian的入门案例,客户端
HessianProxyFactory factory = new HessianProxyFactory();
try {
HelloHessian helloHessian = (HelloHessian) factory.create(HelloHessian.class, "http://localhost:8080/hessian_web/hessian");
helloHessian.sayHello("hi~~~~~~");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
仅仅有三行重要的代码,那么hessianProxyFactory的作用是什么呢?factory.create的内部实现又是怎么样的呢?,调用sayHello方法里面又是怎么实现的呢?带着这些疑问,接下来我们就一步一步来解决这些谜团
1.hessian客户端访问服务端流程:
hessian的主要结构分为客户端和服务端,中间基于http传输。客户端主要做的就是把对远程调用接口序列化为流,并传输给服务端;而服务端主要是接受客户端的请求,将流反序列化并处理,将结果序列化成流再传输给客户端。下面为流程图:
2.hessian是什么呢?
hessian是一种远程通讯协议,它传输的标准格式是二进制文件,而后将二进制文件转化为流(通过序列化方式),以二进制方式传输的方式的好处是可以跨语言进行数据交互,传输便捷,快速
3.HessianProxyFactory通过它的create方法来创建代理类,而这里使用了jdk的动态代理,会自动调用invocationHandler中的invoke方法,HessianProxy实现了InvocationHandler接口
4.接下来就在helloHessian.sayHello(“hi~~~~~~”);
打个断点,然后跟进去,就进入到了invoke方法,
public Object invoke(Object proxy, Method method, Object []args)
throws Throwable
{
String mangleName;
synchronized (_mangleMap) {//_mangleMap里面存放的是接口的方法名 mangleName = _mangleMap.get(method); } if (mangleName == null) { String methodName = method.getName(); Class []params = method.getParameterTypes(); // equals and hashCode are special cased if (methodName.equals("equals") && params.length == 1 && params[0].equals(Object.class)) { Object value = args[0]; if (value == null || ! Proxy.isProxyClass(value.getClass())) return Boolean.FALSE; Object proxyHandler = Proxy.getInvocationHandler(value); if (! (proxyHandler instanceof HessianProxy)) return Boolean.FALSE; HessianProxy handler = (HessianProxy) proxyHandler; return new Boolean(_url.equals(handler.getURL())); } else if (methodName.equals("hashCode") && params.length == 0)//下边是校验方法是否是固定的那些,如果是,那么就进行特殊处理 return new Integer(_url.hashCode()); else if (methodName.equals("getHessianType")) return proxy.getClass().getInterfaces()[0].getName(); else if (methodName.equals("getHessianURL")) return _url.toString(); else if (methodName.equals("toString") && params.length == 0) return "HessianProxy[" + _url + "]"; if (! _factory.isOverloadEnabled()) mangleName = method.getName(); else mangleName = mangleName(method); synchronized (_mangleMap) { _mangleMap.put(method, mangleName);//将接口名放入map中 } } InputStream is = null; URLConnection conn = null; HttpURLConnection httpConn = null; try { if (log.isLoggable(Level.FINER)) log.finer("Hessian[" + _url + "] calling " + mangleName); conn = sendRequest(mangleName, args);//将请求发送给hessian服务端 if (conn instanceof HttpURLConnection) { httpConn = (HttpURLConnection) conn; int code = 500; try { code = httpConn.getResponseCode();//获取响应码 } catch (Exception e) { } parseResponseHeaders(conn);//解析响应头部信息 if (code != 200) { StringBuffer sb = new StringBuffer(); int ch; try { is = httpConn.getInputStream(); if (is != null) { while ((ch = is.read()) >= 0) sb.append((char) ch); is.close(); } is = httpConn.getErrorStream(); if (is != null) { while ((ch = is.read()) >= 0) sb.append((char) ch); } } catch (FileNotFoundException e) { throw new HessianConnectionException("HessianProxy cannot connect to '" + _url, e); } catch (IOException e) { if (is == null) throw new HessianConnectionException(code + ": " + e, e); else throw new HessianConnectionException(code + ": " + sb, e); } if (is != null) is.close(); throw new HessianConnectionException(code + ": " + sb.toString()); } } is = conn.getInputStream(); if (log.isLoggable(Level.FINEST)) { PrintWriter dbg = new PrintWriter(new LogWriter(log)); HessianDebugInputStream dIs = new HessianDebugInputStream(is, dbg); dIs.startTop2(); is = dIs; } AbstractHessianInput in; int code = is.read(); if (code == 'H') { int major = is.read(); int minor = is.read(); in = _factory.getHessian2Input(is); return in.readReply(method.getReturnType()); } else if (code == 'r') { in = _factory.getHessianInput(is); in.startReply(); Object value = in.readObject(method.getReturnType()); if (value instanceof InputStream) { value = new ResultInputStream(httpConn, is, in, (InputStream) value); is = null; httpConn = null; } else in.completeReply(); return value; } else throw new HessianProtocolException("'" + (char) code + "' is an unknown code"); } catch (HessianProtocolException e) { throw new HessianRuntimeException(e); } finally { try { if (is != null) is.close(); } catch (Exception e) { log.log(Level.FINE, e.toString(), e); } try { if (httpConn != null) httpConn.disconnect(); } catch (Exception e) { log.log(Level.FINE, e.toString(), e); } }
}
invoke方法中的最重要的几行代码
conn = sendRequest(mangleName, args);//将请求发送给hessian服务端
这行代码主要是建立与服务端的连接并发送请求给服务端,接着我们就跟进去这个方法
URLConnection conn = null;
conn = _factory.openConnection(_url);//打开与hessian服务器的连接
boolean isValid = false;
try {
// Used chunked mode when available, i.e. JDK 1.5.
if (_factory.isChunkedPost() && conn instanceof HttpURLConnection) {
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;//转成HttpURLConnection
httpConn.setChunkedStreamingMode(8 * 1024);
} catch (Throwable e) {
}
}
addRequestHeaders(conn);//填充请求头部信息
OutputStream os = null;
try {
os = conn.getOutputStream();
} catch (Exception e) {
throw new HessianRuntimeException(e);
}
if (log.isLoggable(Level.FINEST)) {
PrintWriter dbg = new PrintWriter(new LogWriter(log));
os = new HessianDebugOutputStream(os, dbg);
}
AbstractHessianOutput out = _factory.getHessianOutput(os);//获得hessian封装好的输出流
out.call(methodName, args);//里面就是将方法与参数进行序列化
out.flush();
isValid = true;
return conn;
} finally {
if (! isValid && conn instanceof HttpURLConnection)
((HttpURLConnection) conn).disconnect();
}
接着再跟进out.call(method ,args)方法
int length = args != null ? args.length : 0;
startCall(method, length);//发送连接前准备
for (int i = 0; i < length; i++)
writeObject(args[i]);//将参数序列化
completeCall();//发送后处理
writeObject(args[i])方法就是讲参数进行序列化,再跟进去看看是如何进行序列化的
if (object == null) {
writeNull();
return;
}
Serializer serializer;
serializer = _serializerFactory.getSerializer(object.getClass());//获得序列化工厂
serializer.writeObject(object, this);这里获取序列化工厂,在通过序列化实例将参数进行序列化,再跟进去
switch (code) {
case BOOLEAN:
out.writeBoolean(((Boolean) obj).booleanValue());
break;
case BYTE:
case SHORT:
case INTEGER:
out.writeInt(((Number) obj).intValue());
break;
case LONG:
out.writeLong(((Number) obj).longValue());
break;
case FLOAT:
case DOUBLE:
out.writeDouble(((Number) obj).doubleValue());
break;
case CHARACTER:
case CHARACTER_OBJECT:
out.writeString(String.valueOf(obj));
break;
case STRING:
out.writeString((String) obj);
break;
case DATE:
out.writeUTCDate(((Date) obj).getTime());
break;
case BOOLEAN_ARRAY:
{
if (out.addRef(obj))
return;
boolean []data = (boolean []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[boolean");
for (int i = 0; i < data.length; i++)
out.writeBoolean(data[i]);
if (hasEnd)
out.writeListEnd();
break;
}
case BYTE_ARRAY:
{
byte []data = (byte []) obj;
out.writeBytes(data, 0, data.length);
break;
}
case SHORT_ARRAY:
{
if (out.addRef(obj))
return;
short []data = (short []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[short");
for (int i = 0; i < data.length; i++)
out.writeInt(data[i]);
if (hasEnd)
out.writeListEnd();
break;
}
case INTEGER_ARRAY:
{
if (out.addRef(obj))
return;
int []data = (int []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[int");
for (int i = 0; i < data.length; i++)
out.writeInt(data[i]);
if (hasEnd)
out.writeListEnd();
break;
}
case LONG_ARRAY:
{
if (out.addRef(obj))
return;
long []data = (long []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[long");
for (int i = 0; i < data.length; i++)
out.writeLong(data[i]);
if (hasEnd)
out.writeListEnd();
break;
}
case FLOAT_ARRAY:
{
if (out.addRef(obj))
return;
float []data = (float []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[float");
for (int i = 0; i < data.length; i++)
out.writeDouble(data[i]);
if (hasEnd)
out.writeListEnd();
break;
}
case DOUBLE_ARRAY:
{
if (out.addRef(obj))
return;
double []data = (double []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[double");
for (int i = 0; i < data.length; i++)
out.writeDouble(data[i]);
if (hasEnd)
out.writeListEnd();
break;
}
case STRING_ARRAY:
{
if (out.addRef(obj))
return;
String []data = (String []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[string");
for (int i = 0; i < data.length; i++) {
out.writeString(data[i]);
}
if (hasEnd)
out.writeListEnd();
break;
}
case CHARACTER_ARRAY:
{
char []data = (char []) obj;
out.writeString(data, 0, data.length);
break;
}
case OBJECT_ARRAY:
{
if (out.addRef(obj))
return;
Object []data = (Object []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[object");
for (int i = 0; i < data.length; i++) {
out.writeObject(data[i]);
}
if (hasEnd)
out.writeListEnd();
break;
}
case NULL:
out.writeNull();
break;
default:
throw new RuntimeException(code + " " + String.valueOf(obj.getClass()));
}
以上代码片段就是对参数进行序列化,客户端的源码分析就到这里,服务端的今后会继续更新,由于本人目前水平有限,对序列化原理还处于比较模糊的状态,下面给大家推荐一篇讲解序列化的文章:
http://www.cnblogs.com/redcreen/articles/1955307.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。