Hessian源码分析--HessianProxy
在上一篇博客 Hessian源码分析--HessianProxyFactory 中我们了解到,客户端获得的对象其实是HessianProxy生成的目标对象,当调用目标对象的方法时,会调用HessianProxy的invoke方法,如下,当调用HelloService的helloWorld函数时,会调用HessianProxy的invoke函数(对代理机制不懂的同学可以去学习一下)。
HessianProxyFactory factory = new HessianProxyFactory();
HelloService helloService = (HelloService) factory.create(HelloService.class, url);
System.out.println(helloService.helloWorld("world"));
接下来我们一步一步分析invoke函数,就会对Hessian的机制有一个比较清楚的了解:
invoke方法参数如下
/**
* Handles the object invocation.
*
* @param proxy 就是HessianProxy
* @param method 调用的方法
* @param args 方法需要的参数
*/
public Object invoke(Object proxy, Method method, Object []args)
throws Throwable
String mangleName;
//方法对象对应的名称缓存起来
synchronized (_mangleMap) {
mangleName = _mangleMap.get(method);
}
if (mangleName == null) {
//获得方法名称
String methodName = method.getName();
//方法参数对象类型
Class<?> []params = method.getParameterTypes();
// equals and hashCode are special cased
//如果调用的方法是equals或者hashCode就特殊处理,不用远程调用
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);
}
}
这部分操作是Hessian的关键,sendRequest就是向服务端发送请求,这期间还包括对参数值的序列化,发送请求之后,服务端会根据参数来调用服务端函数并将调用结果序列化之后返回,这样就可以通过conn.getInputStream来获得返回结果,
InputStream is = null;
HessianConnection conn = null;
try {
if (log.isLoggable(Level.FINER))
log.finer("Hessian[" + _url + "] calling " + mangleName);
//向server发送请求,包括函数名及函数的参数
conn = sendRequest(mangleName, args);
//获取请求调用之后的返回值
is = getInputStream(conn);
if (log.isLoggable(Level.FINEST)) {
PrintWriter dbg = new PrintWriter(new LogWriter(log));
HessianDebugInputStream dIs
= new HessianDebugInputStream(is, dbg);
dIs.startTop2();
is = dIs;
}
上面我们大体分析了一下sendRequest函数,接下来我们详细介绍一下这个函数的具体操作:
首先会根据URL来通过获得conn连接对象,接下来通过addRequestHeaders来设置一些默认的头部信息,
通过conn.getOutputStream()来获取OutputStream对象,根据OutputStream对象接下来获得Hessian提供的序列化对象out,
调用out.call(methodName, args)来序列化需要远程调用的函数名称和参数值,out.flush();将传递的数据刷新到outputStream中,
最后通过调用 conn.sendRequest();来发送请求,这个时候服务暴露端会得到这个请求(具体请求执行我们接下来分析)
并返回conn,此时调用结果值应该在conn的InputStream中了。
protected HessianConnection sendRequest(String methodName, Object []args)
throws IOException
{
HessianConnection conn = null;
//根据URL获取链接对象
conn = _factory.getConnectionFactory().open(_url);
boolean isValid = false;
try {
//在请求中设置一些头的默认值
addRequestHeaders(conn);
OutputStream os = null;
try {
//获取OutputStream
os = conn.getOutputStream();
} catch (Exception e) {
throw new HessianRuntimeException(e);
}
if (log.isLoggable(Level.FINEST)) {
PrintWriter dbg = new PrintWriter(new LogWriter(log));
HessianDebugOutputStream dOs = new HessianDebugOutputStream(os, dbg);
dOs.startTop2();
os = dOs;
}
AbstractHessianOutput out = _factory.getHessianOutput(os);
//对函数名和参数值进行二进制序列化
out.call(methodName, args);
out.flush();
//向暴露的服务端发送请求
conn.sendRequest();
isValid = true;
return conn;
} finally {
if (! isValid && conn != null)
conn.destroy();
}
}
当服务暴露端返回值之后,接下来就是返回值的处理了,因为服务端给我们的也是二进制数据,所以我们需要感觉函数参数的类型来反序列化得到结果,上面我们已经分析到
is = getInputStream(conn),这样返回值就在is中,首先第一个读到的是一个code,这样应该是一个标记值,接下来读到的就是主版本号和副版本号了,
in = _factory.getHessian2Input(is)是用来获得反序列化对象
Object value = in.readReply(method.getReturnType()) 这样就可以根据方法的返回类型来反序列化结果值了,这样整个的Hessian的客户端的实现机制就是这样了。
AbstractHessianInput in;
int code = is.read();
if (code == 'H') {
int major = is.read();
int minor = is.read();
in = _factory.getHessian2Input(is);
Object value = in.readReply(method.getReturnType());
return value;
}
else if (code == 'r') {
int major = is.read();
int minor = is.read();
in = _factory.getHessianInput(is);
in.startReplyBody();
Object value = in.readObject(method.getReturnType());
if (value instanceof InputStream) {
value = new ResultInputStream(conn, is, in, (InputStream) value);
is = null;
conn = null;
}
else
in.completeReply();
return value;
接下来我们会对序列化和反序列化机制,已经连接请求机制也会简单分析。
HessianProxy的完整源码解析:
public class HessianProxy implements InvocationHandler, Serializable {
private static final Logger log
= Logger.getLogger(HessianProxy.class.getName());
protected HessianProxyFactory _factory;
private WeakHashMap<Method,String> _mangleMap
= new WeakHashMap<Method,String>();
private Class<?> _type;
private URL _url;
protected HessianProxy(URL url, HessianProxyFactory factory)
{
this(url, factory, null);
}
protected HessianProxy(URL url,
HessianProxyFactory factory,
Class<?> type)
{
_factory = factory;
_url = url;
_type = type;
}
public URL getURL()
{
return _url;
}
/**
* Handles the object invocation.
*
* @param proxy 就是HessianProxy
* @param method 调用的方法
* @param args 方法需要的参数
*/
public Object invoke(Object proxy, Method method, Object []args)
throws Throwable
{
String mangleName;
//方法对象对应的名称缓存起来
synchronized (_mangleMap) {
mangleName = _mangleMap.get(method);
}
if (mangleName == null) {
//获得方法名称
String methodName = method.getName();
//方法参数对象类型
Class<?> []params = method.getParameterTypes();
// equals and hashCode are special cased
//如果调用的方法是equals或者hashCode就特殊处理,不用远程调用
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);
}
}
InputStream is = null;
HessianConnection conn = null;
try {
if (log.isLoggable(Level.FINER))
log.finer("Hessian[" + _url + "] calling " + mangleName);
//向server发送请求,包括函数名及函数的参数
conn = sendRequest(mangleName, args);
//获取请求调用之后的返回值
is = getInputStream(conn);
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();
//获得对象Hessian2Input
in = _factory.getHessian2Input(is);
//根据方法返回值类型,反序列化获得返回值
Object value = in.readReply(method.getReturnType());
return value;
}
else if (code == 'r') {
int major = is.read();
int minor = is.read();
in = _factory.getHessianInput(is);
in.startReplyBody();
Object value = in.readObject(method.getReturnType());
if (value instanceof InputStream) {
value = new ResultInputStream(conn, is, in, (InputStream) value);
is = null;
conn = 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 (conn != null)
conn.destroy();
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
}
}
//获取HessianConnection中的返回值
protected InputStream getInputStream(HessianConnection conn)
throws IOException
{
InputStream is = conn.getInputStream();
if ("deflate".equals(conn.getContentEncoding())) {
is = new InflaterInputStream(is, new Inflater(true));
}
return is;
}
protected String mangleName(Method method)
{
Class<?> []param = method.getParameterTypes();
if (param == null || param.length == 0)
return method.getName();
else
return AbstractSkeleton.mangleName(method, false);
}
/**
* Sends the HTTP request to the Hessian connection.
*/
protected HessianConnection sendRequest(String methodName, Object []args)
throws IOException
{
HessianConnection conn = null;
//根据URL获取链接对象
conn = _factory.getConnectionFactory().open(_url);
boolean isValid = false;
try {
//在请求中设置一些头的默认值
addRequestHeaders(conn);
OutputStream os = null;
try {
//获取OutputStream
os = conn.getOutputStream();
} catch (Exception e) {
throw new HessianRuntimeException(e);
}
if (log.isLoggable(Level.FINEST)) {
PrintWriter dbg = new PrintWriter(new LogWriter(log));
HessianDebugOutputStream dOs = new HessianDebugOutputStream(os, dbg);
dOs.startTop2();
os = dOs;
}
AbstractHessianOutput out = _factory.getHessianOutput(os);
//对函数名和参数值进行二进制序列化
out.call(methodName, args);
out.flush();
//向暴露的服务端发送请求
conn.sendRequest();
isValid = true;
return conn;
} finally {
if (! isValid && conn != null)
conn.destroy();
}
}
//在请求中设置一些头的默认值
protected void addRequestHeaders(HessianConnection conn)
{
conn.addHeader("Content-Type", "x-application/hessian");
conn.addHeader("Accept-Encoding", "deflate");
String basicAuth = _factory.getBasicAuth();
if (basicAuth != null)
conn.addHeader("Authorization", basicAuth);
}
/**
* Method that allows subclasses to parse response headers such as cookies.
* Default implementation is empty.
* @param conn
*/
protected void parseResponseHeaders(URLConnection conn)
{
}
public Object writeReplace()
{
return new HessianRemote(_type.getName(), _url.toString());
}
static class ResultInputStream extends InputStream {
private HessianConnection _conn;
private InputStream _connIs;
private AbstractHessianInput _in;
private InputStream _hessianIs;
ResultInputStream(HessianConnection conn,
InputStream is,
AbstractHessianInput in,
InputStream hessianIs)
{
_conn = conn;
_connIs = is;
_in = in;
_hessianIs = hessianIs;
}
public int read()
throws IOException
{
if (_hessianIs != null) {
int value = _hessianIs.read();
if (value < 0)
close();
return value;
}
else
return -1;
}
public int read(byte []buffer, int offset, int length)
throws IOException
{
if (_hessianIs != null) {
int value = _hessianIs.read(buffer, offset, length);
if (value < 0)
close();
return value;
}
else
return -1;
}
public void close()
throws IOException
{
HessianConnection conn = _conn;
_conn = null;
InputStream connIs = _connIs;
_connIs = null;
AbstractHessianInput in = _in;
_in = null;
InputStream hessianIs = _hessianIs;
_hessianIs = null;
try {
if (hessianIs != null)
hessianIs.close();
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
try {
if (in != null) {
in.completeReply();
in.close();
}
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
try {
if (connIs != null) {
connIs.close();
}
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
try {
if (conn != null) {
conn.close();
}
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
}
}
//日志相关
static class LogWriter extends Writer {
private Logger _log;
private Level _level = Level.FINEST;
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.log(_level, _sb.toString());
_sb.setLength(0);
}
else
_sb.append((char) ch);
}
}
public void flush()
{
}
public void close()
{
if (_sb.length() > 0)
_log.log(_level, _sb.toString());
}
}
}
Hessian源码分析--HessianProxy的更多相关文章
- Hessian源码分析--总体架构
Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebService,Hessian更简单.快捷.采用的是二进制RPC协议,因为采用的是二进制协 ...
- Hessian源码分析--HessianSkeleton
HessianSkeleton是Hessian的服务端的核心,简单总结来说:HessianSkeleton根据客户端请求的链接,获取到需要执行的接口及实现类,对客户端发送过来的二进制数据进行反序列化, ...
- (转)hessian源码分析(一)------架构
在计费中心的对外交互这块采用了hessian,有必要对hessian的运行机理和源码做一定的解析. 大致翻了翻源码后,发现hessian的主要结构分客户端与服务端,中间基于http传输.客户端主要做的 ...
- Hessian源码分析--HessianProxyFactory
HessianProxyFactory是HessianProxy的工厂类,其通过HessianProxy来生成代理类. 如下面代码: HessianProxyFactory factory = new ...
- Hessian源码分析--HessianServlet
Hessian可以通过Servlet来对外暴露服务,HessianServlet继承于HttpServlet,但这仅仅是一个外壳,使用web服务器来提供对外的Http请求,在web.xml中我们会进行 ...
- 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. 源码分析- ...
随机推荐
- C语言第五次作业——循环结构
C语言程序设计第五次作业--循环结构(1) (一)改错题 输出华氏摄氏温度转换表:输入两个整数lower和upper,输出一张华氏摄氏温度转换表,华氏温度的取值范围是{lower,upper},每次增 ...
- left join 连表时,on后多条件无效问题
http://www.cnblogs.com/guixiaoming/p/6516261.html left join 连表时,on后多条件无效问题 最近开发素材库项目,各种关系复杂的表,一度6张表的 ...
- Java的五子棋实现
Java 五子棋 注:除机器人算法外其余借鉴于MLDN. package MyFiveChess; import robot.*; import java.awt.*; import javax.sw ...
- 利用css3+js实现简单带立体过渡效果的图片切换(chrome浏览器)
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...
- bootmgr is missing 开机无法进系统怎么办
认识 bootmgr: 启动管理器.Bootmgr是Boot Manager的缩写,是在Windows Vista和Windows 7中使用的新的启动管理器,以代替Windows xp中的启动管理器- ...
- JS判断PC还是移动端打开网页
最近在做移动端网站,也需兼容PC端.还没找到更好的方法,只能用javascr判断用户是在PC端打开还是移动端打开. JS判断 var isPC = function (){ var userAg ...
- JavaScript DOM详解
欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52727448 本文出自:[余志强的博客] 一.DOM概述 D: Do ...
- 浅析"Sublabel-Accurate Relaxation of Nonconvex Energies" CVPR 2016 Best Paper Honorable Mention
今天作了一个paper reading,感觉论文不错,马克一下~ CVPR 2016 Best Paper Honorable Mention "Sublabel-Accurate Rela ...
- ROS_Kinetic_29 kamtoa simulation学习与示例分析(一)
致谢源代码网址:https://github.com/Tutorgaming/kamtoa-simulation kamtoa simulation学习与示例分析(一) 源码学习与分析是学习ROS,包 ...
- 给定一数组,输出满足2a=b(a,b代表数组中的数)的数对,要求时间复杂度尽量低。
//时间复杂度O(n),空间复杂度O(n) void findSequence(int* arr, int len) { int* hashtable = new int[RANGE]; memset ...