基于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>
先放张类关系图:
根据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>
同理:
主要流程:
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);
利用反射调用具体的实现方法。中间掺杂着反序列化,校验,序列化的其他方法。
有些地方自己也不是很懂,主要是记录大体的流程,细节后续再细究吧。