hessian 源码
场景:Hessian源码学习(1)
Hessian源码学习(一)
【服务端】
HessianServlet 是一个非常普通的Servlet 它直接继承 GenericServlet
我们重点看其中的两个方法:
1.init(ServletConfig config)
这个方法覆写父类的init(ServletConfig config)方法 (我觉得这里覆写init()方法更好)
在初始化中,它做了哪些事情呢?
a.初始化远程服务类(Impl)
其中home-class或者service-class就是在web.xml配置的提供远程服务的类
它首先通过getInitParameter方法获取类名,然后调用loadClass获取对应的Class,最后newInstance创建实例
init(_homeImpl) 又做了些什么呢?
我们知道提供远程服务的类是继承HessianServlet的 所以它也是一个Servlet 我们同样需要初始化它(以下是初始化代码)
b.初始化远程服务类(Interface)
这段代码和上面逻辑基本一样,这里不再赘述。
c.初始化 HessianSkeleton 类
重点在于super(apiClass):AbstractSkeleton的初始化
Method []methodList = apiClass.getMethods();
获取服务类的所有public方法,这也是为什么hessian说每一个public方法都是一个远程服务。
接着遍历所有方法,放入_methodMap中,这里有个关键点,如何支持重载?
hessian是这样处理的,比如对于一个方法: public void sayHello(String str),那么在_methodMap中会存放三个key
sayHello
sayHello_1 (参数个数)
sayHello_string (参数类型)
所以只要client传递方法说明支持调用重载方法,那么他就会调用到正确的重载方法,不然结果是不确定的。
2.service(ServletRequest request, ServletResponse response)
这个方法重写了父类的service方法
a.检查请求方式是否是post
b.初始化Hessian输入流以及序列化工厂并设置到Hessian输入流
c.读取第一个字节判断是否标准的hessian流
d.生成hessian输出流并设置序列化工厂到输出流
e.调用服务
我们具体看下HessianSkeleton.invoke方法:
很感谢你的支持,我自己也是出于好奇和以及学习的目的来看hessian源码的,本身并没有什么使用经验。
原理的话我想一步步分析源码就可以得出,至于设计思路这个问题我还回答不上来,希望能和你共同探讨,另外后面也打算分析几个类以及hessian如何实现序列化与反序列化。
Hessian源码学习(一)
【服务端】
HessianServlet 是一个非常普通的Servlet 它直接继承 GenericServlet
我们重点看其中的两个方法:
1.init(ServletConfig config)
这个方法覆写父类的init(ServletConfig config)方法 (我觉得这里覆写init()方法更好)
在初始化中,它做了哪些事情呢?
a.初始化远程服务类(Impl)
if (_homeImpl != null) { } else if (getInitParameter("home-class") != null) { String className = getInitParameter("home-class"); Class homeClass = loadClass(className); _homeImpl = homeClass.newInstance(); init(_homeImpl); } else if (getInitParameter("service-class") != null) { String className = getInitParameter("service-class"); Class homeClass = loadClass(className); _homeImpl = homeClass.newInstance(); init(_homeImpl); }
其中home-class或者service-class就是在web.xml配置的提供远程服务的类
它首先通过getInitParameter方法获取类名,然后调用loadClass获取对应的Class,最后newInstance创建实例
init(_homeImpl) 又做了些什么呢?
我们知道提供远程服务的类是继承HessianServlet的 所以它也是一个Servlet 我们同样需要初始化它(以下是初始化代码)
private void init(Object service) throws ServletException { if (service instanceof Service) ((Service) service).init(getServletConfig()); else if (service instanceof Servlet) ((Servlet) service).init(getServletConfig()); }
b.初始化远程服务类(Interface)
if (_homeAPI != null) { } else if (getInitParameter("home-api") != null) { String className = getInitParameter("home-api"); _homeAPI = loadClass(className); } else if (getInitParameter("api-class") != null) { String className = getInitParameter("api-class"); _homeAPI = loadClass(className); } else if (_homeImpl != null) { _homeAPI = findRemoteAPI(_homeImpl.getClass()); if (_homeAPI == null) _homeAPI = _homeImpl.getClass(); }
这段代码和上面逻辑基本一样,这里不再赘述。
c.初始化 HessianSkeleton 类
public HessianSkeleton(Object service, Class apiClass) { super(apiClass); _service = service; if (! apiClass.isAssignableFrom(service.getClass())) throw new IllegalArgumentException("Service " + service + " must be an instance of " + apiClass.getName()); }
重点在于super(apiClass):AbstractSkeleton的初始化
protected AbstractSkeleton(Class apiClass) { _apiClass = apiClass; Method []methodList = apiClass.getMethods(); for (int i = 0; i < methodList.length; i++) { Method method = methodList[i]; if (_methodMap.get(method.getName()) == null) _methodMap.put(method.getName(), methodList[i]); Class []param = method.getParameterTypes(); String mangledName = method.getName() + "__" + param.length; _methodMap.put(mangledName, methodList[i]); _methodMap.put(mangleName(method, false), methodList[i]); } }
Method []methodList = apiClass.getMethods();
获取服务类的所有public方法,这也是为什么hessian说每一个public方法都是一个远程服务。
接着遍历所有方法,放入_methodMap中,这里有个关键点,如何支持重载?
hessian是这样处理的,比如对于一个方法: public void sayHello(String str),那么在_methodMap中会存放三个key
sayHello
sayHello_1 (参数个数)
sayHello_string (参数类型)
所以只要client传递方法说明支持调用重载方法,那么他就会调用到正确的重载方法,不然结果是不确定的。
2.service(ServletRequest request, ServletResponse response)
这个方法重写了父类的service方法
a.检查请求方式是否是post
if (! req.getMethod().equals("POST")) { res.setStatus(500, "Hessian Requires POST"); PrintWriter out = res.getWriter(); res.setContentType("text/html"); out.println("<h1>Hessian Requires POST</h1>"); return; }
b.初始化Hessian输入流以及序列化工厂并设置到Hessian输入流
Hessian2Input in = new Hessian2Input(is); SerializerFactory serializerFactory = getSerializerFactory(); in.setSerializerFactory(serializerFactory);
c.读取第一个字节判断是否标准的hessian流
int code = in.read(); if (code != 'c') { throw new IOException("expected 'c' in hessian input at " + code); }
d.生成hessian输出流并设置序列化工厂到输出流
out = new HessianOutput(os); out.setSerializerFactory(serializerFactory);
e.调用服务
_homeSkeleton.invoke(in, out);
我们具体看下HessianSkeleton.invoke方法:
//反序列化输入流获取调用的服务方法 String methodName = in.readMethod(); Method method = getMethod(methodName); //反序列输入流获取方法参数 Class []args = method.getParameterTypes(); Object []values = new Object[args.length]; for (int i = 0; i < args.length; i++) values[i] = in.readObject(args[i]); // 真正的执行服务方法(java 反射) result = method.invoke(_service, values); //最后把执行写回输出流,输出起始标志:'r' 1 0 out.startReply(); // 序列化结果 out.writeObject(result); // 输出结束标志'z' out.completeReply();
1 楼
evanzzy
2011-11-28
支持继续发布Hessian分析类文章。另外lz是否可讲解hessian相关原理和设计思路?谢谢。
2 楼
DiaoCow
2011-11-28
evanzzy 写道
支持继续发布Hessian分析类文章。另外lz是否可讲解hessian相关原理和设计思路?谢谢。
很感谢你的支持,我自己也是出于好奇和以及学习的目的来看hessian源码的,本身并没有什么使用经验。
原理的话我想一步步分析源码就可以得出,至于设计思路这个问题我还回答不上来,希望能和你共同探讨,另外后面也打算分析几个类以及hessian如何实现序列化与反序列化。