hessian 源码

场景:Hessian源码学习(1)

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如何实现序列化与反序列化。