基于springmvc的hessian调用原理浅析

一、客户端

1、构造(初始化)

由客户端的配置文件随容器的启动而进行初始化,配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:/server.properties" ignore-unresolvable="true"/> <bean id="application"
class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl">
<value>${app_server_path}</value>
</property>
<property name="serviceInterface">
<value>com.avatarmind.server.service.ApplicationService</value>
</property>
</bean> </beans>

先放张类关系图:

基于springmvc的hessian调用原理浅析

根据spring生命周期可知,容器初始化,会调用InitializingBean的afterPropertiesSet()方法,

而HessianProxyFactoryBean类实现了InitializingBean接口并重写了afterPropertiesSet()方法。

所以主要流程为:

1)、HessianProxyFactoryBean的afterPropertiesSet()

2)、HessianClientInterceptor的afterPropertiesSet()

3)、HessianClientInterceptor的prepare()

4)、HessianClientInterceptor的createHessianProxy(HessianProxyFactory proxyFactory)

5)、HessianProxyFactory的create(Class<?> api, String urlName, ClassLoader loader)

  public Object create(Class<?> api, URL url, ClassLoader loader)
{
if (api == null)
throw new NullPointerException("api must not be null for HessianProxyFactory.create()");
InvocationHandler handler = null; handler = new HessianProxy(url, this, api); return Proxy.newProxyInstance(loader,
new Class[] { api,
HessianRemoteObject.class },
handler);
}

整个流程最终就是为服务接口生成代理类。

2、使用接口调用服务

具体的方法调用我就不写了,不知道的可以看我以前写的hessian的基本使用。

由public class HessianProxy implements InvocationHandler, Serializable和构造的第 5)里的代码可知

接口的调用会转到HessianProxy的invoke(Object proxy, Method method, Object []args)方法里。

具体的代码如下,有些细节我也不是很懂,好像就是序列化、发送请求(conn = sendRequest(mangleName, 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
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);
// 调用服务端
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(); 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);
}
}
}

二、服务端

1、构造(初始化)

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- app -->
<bean id="applicationServiceImpl" class="com.server.service.impl.ApplicationServiceImpl" /> <!-- 使用HessianServiceExporter 将普通bean导出成Hessian服务 -->
<bean name="/app"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="applicationServiceImpl" />
<!-- Hessian服务的接口 -->
<property name="serviceInterface" value="com.server.service.ApplicationService" />
</bean> </beans>

同理:

基于springmvc的hessian调用原理浅析

主要流程:

1)、HessianExporter的afterPropertiesSet()

2)、HessianExporter的prepare()

3)、RemoteExporter的getProxyForService()

流程主要是生成HessianSkeleton类的对象。

因为配置文件的bean的name带 / 符号,所以会被BeanNameUrlHandlerMapping进行映射处理。

2、被调用

由于基于mvc,所以请求会先到DispatcherServlet的doDispatch方法,然后根据路径获取handler,

因此服务的入口为HessianServiceExporter的handleRequest()方法。

    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { // 验证服务是否启动成功的地方
if (!"POST".equals(request.getMethod())) {
throw new HttpRequestMethodNotSupportedException(request.getMethod(),
new String[] {"POST"}, "HessianServiceExporter only supports POST requests");
} response.setContentType(CONTENT_TYPE_HESSIAN);
try {
// 调用
invoke(request.getInputStream(), response.getOutputStream());
}
catch (Throwable ex) {
throw new NestedServletException("Hessian skeleton invocation failed", ex);
}
}

流程:

1)、HessianServiceExporter的handleRequest()

2)、HessianExporter的invoke(InputStream inputStream, OutputStream outputStream)

3)、HessianExporter的doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)

核心代码:skeleton.invoke(in, out);

4)、HessianSkeleton的invoke()

核心代码:result = method.invoke(service, values);

利用反射调用具体的实现方法。中间掺杂着反序列化,校验,序列化的其他方法。

有些地方自己也不是很懂,主要是记录大体的流程,细节后续再细究吧。

上一篇:使用Apache Archiva搭建Maven Repository Server


下一篇:Make github as your personal maven repository